xref: /OK3568_Linux_fs/kernel/drivers/power/supply/rk817_charger.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * rk817 charger driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2018 Rockchip Electronics Co., Ltd
5*4882a593Smuzhiyun  * xsf <xsf@rock-chips.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify it
8*4882a593Smuzhiyun  * under the terms and conditions of the GNU General Public License,
9*4882a593Smuzhiyun  * version 2, as published by the Free Software Foundation.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * This program is distributed in the hope it will be useful, but WITHOUT
12*4882a593Smuzhiyun  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14*4882a593Smuzhiyun  * more details.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/extcon.h>
20*4882a593Smuzhiyun #include <linux/gpio.h>
21*4882a593Smuzhiyun #include <linux/iio/consumer.h>
22*4882a593Smuzhiyun #include <linux/iio/iio.h>
23*4882a593Smuzhiyun #include <linux/irq.h>
24*4882a593Smuzhiyun #include <linux/jiffies.h>
25*4882a593Smuzhiyun #include <linux/mfd/rk808.h>
26*4882a593Smuzhiyun #include <linux/module.h>
27*4882a593Smuzhiyun #include <linux/of_device.h>
28*4882a593Smuzhiyun #include <linux/of_gpio.h>
29*4882a593Smuzhiyun #include <linux/platform_device.h>
30*4882a593Smuzhiyun #include <linux/power_supply.h>
31*4882a593Smuzhiyun #include <linux/power/rk_usbbc.h>
32*4882a593Smuzhiyun #include <linux/regmap.h>
33*4882a593Smuzhiyun #include <linux/rtc.h>
34*4882a593Smuzhiyun #include <linux/timer.h>
35*4882a593Smuzhiyun #include <linux/workqueue.h>
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun static int dbg_enable;
38*4882a593Smuzhiyun module_param_named(dbg_level, dbg_enable, int, 0644);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define DBG(args...) \
41*4882a593Smuzhiyun 	do { \
42*4882a593Smuzhiyun 		if (dbg_enable) { \
43*4882a593Smuzhiyun 			pr_info(args); \
44*4882a593Smuzhiyun 		} \
45*4882a593Smuzhiyun 	} while (0)
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define CHARGE_DRIVER_VERSION		"1.0"
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #define DISABLE	0x00
50*4882a593Smuzhiyun #define ENABLE	0x01
51*4882a593Smuzhiyun #define OTG_SLP_ENABLE	0x01
52*4882a593Smuzhiyun #define OTG_SLP_DISABLE	0x00
53*4882a593Smuzhiyun #define OTG_ENABLE		0x11
54*4882a593Smuzhiyun #define OTG_DISABLE		0x10
55*4882a593Smuzhiyun #define RK817_BOOST_ENABLE	0x11
56*4882a593Smuzhiyun #define RK817_BOOST_DISABLE	0x10
57*4882a593Smuzhiyun #define OTG_MODE		0x01
58*4882a593Smuzhiyun #define OTG_MODE_ON		0x01
59*4882a593Smuzhiyun #define DEFAULT_INPUT_VOLTAGE	4500
60*4882a593Smuzhiyun #define DEFAULT_INPUT_CURRENT	2000
61*4882a593Smuzhiyun #define DEFAULT_CHRG_VOLTAGE	4200
62*4882a593Smuzhiyun #define DEFAULT_CHRG_CURRENT	1400
63*4882a593Smuzhiyun #define DEFAULT_CHRG_TERM_MODE	1
64*4882a593Smuzhiyun #define DEFAULT_CHRG_TERM_CUR		150
65*4882a593Smuzhiyun #define SAMPLE_RES_10MR		10
66*4882a593Smuzhiyun #define SAMPLE_RES_20MR		20
67*4882a593Smuzhiyun #define SAMPLE_RES_DIV1		1
68*4882a593Smuzhiyun #define SAMPLE_RES_DIV2		2
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define INPUT_450MA		450
71*4882a593Smuzhiyun #define INPUT_1500MA	1500
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define CURRENT_TO_ADC(current, samp_res)	\
74*4882a593Smuzhiyun 	(current * 1000 * samp_res / 172)
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun enum charge_current {
77*4882a593Smuzhiyun 	CHRG_CUR_1000MA,
78*4882a593Smuzhiyun 	CHRG_CUR_1500MA,
79*4882a593Smuzhiyun 	CHRG_CUR_2000MA,
80*4882a593Smuzhiyun 	CHRG_CUR_2500MA,
81*4882a593Smuzhiyun 	CHRG_CUR_2750MA,
82*4882a593Smuzhiyun 	CHRG_CUR_3000MA,
83*4882a593Smuzhiyun 	CHRG_CUR_3500MA,
84*4882a593Smuzhiyun 	CHRG_CUR_500MA,
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun enum charge_voltage {
88*4882a593Smuzhiyun 	CHRG_VOL_4100MV,
89*4882a593Smuzhiyun 	CHRG_VOL_4150MV,
90*4882a593Smuzhiyun 	CHRG_VOL_4200MV,
91*4882a593Smuzhiyun 	CHRG_VOL_4250MV,
92*4882a593Smuzhiyun 	CHRG_VOL_4300MV,
93*4882a593Smuzhiyun 	CHRG_VOL_4350MV,
94*4882a593Smuzhiyun 	CHRG_VOL_4400MV,
95*4882a593Smuzhiyun 	CHRG_VOL_4450MV,
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun enum input_voltage {
99*4882a593Smuzhiyun 	INPUT_VOL_4000MV,
100*4882a593Smuzhiyun 	INPUT_VOL_4100MV,
101*4882a593Smuzhiyun 	INPUT_VOL_4200MV,
102*4882a593Smuzhiyun 	INPUT_VOL_4300MV,
103*4882a593Smuzhiyun 	INPUT_VOL_4400MV,
104*4882a593Smuzhiyun 	INPUT_VOL_4500MV,
105*4882a593Smuzhiyun 	INPUT_VOL_4600MV,
106*4882a593Smuzhiyun 	INPUT_VOL_4700MV,
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun enum input_current {
110*4882a593Smuzhiyun 	INPUT_CUR_450MA,
111*4882a593Smuzhiyun 	INPUT_CUR_80MA,
112*4882a593Smuzhiyun 	INPUT_CUR_850MA,
113*4882a593Smuzhiyun 	INPUT_CUR_1500MA,
114*4882a593Smuzhiyun 	INPUT_CUR_1750MA,
115*4882a593Smuzhiyun 	INPUT_CUR_2000MA,
116*4882a593Smuzhiyun 	INPUT_CUR_2500MA,
117*4882a593Smuzhiyun 	INPUT_CUR_3000MA,
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun enum charge_clk {
121*4882a593Smuzhiyun 	CHRG_CLK_1M,
122*4882a593Smuzhiyun 	CHRG_CLK_2M,
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun enum charge_term_sel {
126*4882a593Smuzhiyun 	CHRG_TERM_150MA,
127*4882a593Smuzhiyun 	CHRG_TERM_200MA,
128*4882a593Smuzhiyun 	CHRG_TERM_300MA,
129*4882a593Smuzhiyun 	CHRG_TERM_400MA,
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun enum charge_timer_trickle {
133*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_30MIN,
134*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_45MIN,
135*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_60MIN,
136*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_90MIN,
137*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_120MIN,
138*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_150MIN,
139*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_180MIN,
140*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_210MIN,
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun enum charge_timer_cccv {
144*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_4H,
145*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_5H,
146*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_6H,
147*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_8H,
148*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_10H,
149*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_12H,
150*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_14H,
151*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_16H,
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun enum charge_status {
155*4882a593Smuzhiyun 	CHRG_OFF,
156*4882a593Smuzhiyun 	DEAD_CHRG,
157*4882a593Smuzhiyun 	TRICKLE_CHRG,
158*4882a593Smuzhiyun 	CC_OR_CV_CHRG,
159*4882a593Smuzhiyun 	CHRG_TERM,
160*4882a593Smuzhiyun 	USB_OVER_VOL,
161*4882a593Smuzhiyun 	BAT_TMP_ERR,
162*4882a593Smuzhiyun 	BAT_TIM_ERR,
163*4882a593Smuzhiyun };
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun enum discharge_ilimit {
166*4882a593Smuzhiyun 	DISCHRG_2000MA,
167*4882a593Smuzhiyun 	DISCHRG_2500MA,
168*4882a593Smuzhiyun 	DISCHRG_3000MA,
169*4882a593Smuzhiyun 	DISCHRG_3500MA,
170*4882a593Smuzhiyun 	DISCHRG_4000MA,
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun enum bat_system_comp_time {
174*4882a593Smuzhiyun 	DLY_20US,
175*4882a593Smuzhiyun 	DLY_10US,
176*4882a593Smuzhiyun 	DLY_40US,
177*4882a593Smuzhiyun 	DLY_20US_AGAIN,
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun enum charge_term_mode {
181*4882a593Smuzhiyun 	CHRG_ANALOG,
182*4882a593Smuzhiyun 	CHRG_DIGITAL,
183*4882a593Smuzhiyun };
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun enum charger_t {
186*4882a593Smuzhiyun 	USB_TYPE_UNKNOWN_CHARGER,
187*4882a593Smuzhiyun 	USB_TYPE_NONE_CHARGER,
188*4882a593Smuzhiyun 	USB_TYPE_USB_CHARGER,
189*4882a593Smuzhiyun 	USB_TYPE_AC_CHARGER,
190*4882a593Smuzhiyun 	USB_TYPE_CDP_CHARGER,
191*4882a593Smuzhiyun 	DC_TYPE_DC_CHARGER,
192*4882a593Smuzhiyun 	DC_TYPE_NONE_CHARGER,
193*4882a593Smuzhiyun };
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun enum charger_state {
196*4882a593Smuzhiyun 	OFFLINE = 0,
197*4882a593Smuzhiyun 	ONLINE
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun enum rk817_charge_fields {
201*4882a593Smuzhiyun 	BOOST_EN, OTG_EN, OTG_SLP_EN, CHRG_CLK_SEL,
202*4882a593Smuzhiyun 	CHRG_EN, CHRG_VOL_SEL, CHRG_CT_EN, CHRG_CUR_SEL,
203*4882a593Smuzhiyun 	USB_VLIM_EN, USB_VLIM_SEL, USB_ILIM_EN, USB_ILIM_SEL,
204*4882a593Smuzhiyun 	SYS_CAN_SD,  USB_SYS_EN, BAT_OVP_EN, CHRG_TERM_ANA_DIG,
205*4882a593Smuzhiyun 	CHRG_TERM_ANA_SEL,
206*4882a593Smuzhiyun 	CHRG_TERM_DIG,
207*4882a593Smuzhiyun 	BAT_HTS_TS, BAT_LTS_TS,
208*4882a593Smuzhiyun 	CHRG_TIMER_TRIKL_EN, CHRG_TIMER_TRIKL,
209*4882a593Smuzhiyun 	CHRG_TIMER_CCCV_EN, CHRG_TIMER_CCCV,
210*4882a593Smuzhiyun 	BAT_EXS, CHG_STS, BAT_OVP_STS, CHRG_IN_CLAMP,
211*4882a593Smuzhiyun 	USB_EXS, USB_EFF,
212*4882a593Smuzhiyun 	BAT_DIS_ILIM_STS, BAT_SYS_CMP_DLY, BAT_DIS_ILIM_EN,
213*4882a593Smuzhiyun 	BAT_DISCHRG_ILIM,
214*4882a593Smuzhiyun 	PLUG_IN_STS, SOC_REG0, SOC_REG1, SOC_REG2,
215*4882a593Smuzhiyun 	F_MAX_FIELDS
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun static const struct reg_field rk817_charge_reg_fields[] = {
219*4882a593Smuzhiyun 	[SOC_REG0] = REG_FIELD(0x9A, 0, 7),
220*4882a593Smuzhiyun 	[SOC_REG1] = REG_FIELD(0x9B, 0, 7),
221*4882a593Smuzhiyun 	[SOC_REG2] = REG_FIELD(0x9C, 0, 7),
222*4882a593Smuzhiyun 	[BOOST_EN] = REG_FIELD(0xB4, 1, 5),
223*4882a593Smuzhiyun 	[OTG_EN] = REG_FIELD(0xB4, 2, 6),
224*4882a593Smuzhiyun 	[OTG_SLP_EN] = REG_FIELD(0xB5, 6, 6),
225*4882a593Smuzhiyun 	[CHRG_EN] = REG_FIELD(0xE4, 7, 7),
226*4882a593Smuzhiyun 	[CHRG_VOL_SEL] = REG_FIELD(0xE4, 4, 6),
227*4882a593Smuzhiyun 	[CHRG_CT_EN] = REG_FIELD(0xE4, 3, 3),
228*4882a593Smuzhiyun 	[CHRG_CUR_SEL] = REG_FIELD(0xE4, 0, 2),
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	[USB_VLIM_EN] = REG_FIELD(0xE5, 7, 7),
231*4882a593Smuzhiyun 	[USB_VLIM_SEL] = REG_FIELD(0xE5, 4, 6),
232*4882a593Smuzhiyun 	[USB_ILIM_EN] = REG_FIELD(0xE5, 3, 3),
233*4882a593Smuzhiyun 	[USB_ILIM_SEL] = REG_FIELD(0xE5, 0, 2),
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	[SYS_CAN_SD] = REG_FIELD(0xE6, 7, 7),
236*4882a593Smuzhiyun 	[USB_SYS_EN] = REG_FIELD(0xE6, 6, 6),
237*4882a593Smuzhiyun 	[BAT_OVP_EN] = REG_FIELD(0xE6, 3, 3),
238*4882a593Smuzhiyun 	[CHRG_TERM_ANA_DIG] = REG_FIELD(0xE6, 2, 2),
239*4882a593Smuzhiyun 	[CHRG_TERM_ANA_SEL] = REG_FIELD(0xE6, 0, 1),
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	[CHRG_TERM_DIG] = REG_FIELD(0xE7, 0, 7),
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	[BAT_HTS_TS] = REG_FIELD(0xE8, 0, 7),
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	[BAT_LTS_TS] = REG_FIELD(0xE9, 0, 7),
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	[CHRG_TIMER_TRIKL_EN] = REG_FIELD(0xEA, 7, 7),
248*4882a593Smuzhiyun 	[CHRG_TIMER_TRIKL] = REG_FIELD(0xEA, 4, 6),
249*4882a593Smuzhiyun 	[CHRG_TIMER_CCCV_EN] = REG_FIELD(0xEA, 3, 3),
250*4882a593Smuzhiyun 	[CHRG_TIMER_CCCV] = REG_FIELD(0xEA, 0, 2),
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	[BAT_EXS] = REG_FIELD(0xEB, 7, 7),
253*4882a593Smuzhiyun 	[CHG_STS] = REG_FIELD(0xEB, 4, 6),
254*4882a593Smuzhiyun 	[BAT_OVP_STS] = REG_FIELD(0xEB, 3, 3),
255*4882a593Smuzhiyun 	[CHRG_IN_CLAMP] = REG_FIELD(0xEB, 2, 2),
256*4882a593Smuzhiyun 	[USB_EXS] = REG_FIELD(0xEB, 1, 1),
257*4882a593Smuzhiyun 	[USB_EFF] = REG_FIELD(0xEB, 0, 0),
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	[BAT_DIS_ILIM_STS] = REG_FIELD(0xEC, 6, 6),
260*4882a593Smuzhiyun 	[BAT_SYS_CMP_DLY] = REG_FIELD(0xEC, 4, 5),
261*4882a593Smuzhiyun 	[BAT_DIS_ILIM_EN] = REG_FIELD(0xEC, 3, 3),
262*4882a593Smuzhiyun 	[BAT_DISCHRG_ILIM] = REG_FIELD(0xEC, 0, 2),
263*4882a593Smuzhiyun 	[PLUG_IN_STS] = REG_FIELD(0xf0, 6, 6),
264*4882a593Smuzhiyun 	[CHRG_CLK_SEL] = REG_FIELD(0xF3, 6, 6),
265*4882a593Smuzhiyun };
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun struct charger_platform_data {
268*4882a593Smuzhiyun 	u32 max_input_current;
269*4882a593Smuzhiyun 	u32 min_input_voltage;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	u32 max_chrg_current;
272*4882a593Smuzhiyun 	u32 max_chrg_voltage;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	u32 chrg_finish_cur;
275*4882a593Smuzhiyun 	u32 chrg_term_mode;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	u32 power_dc2otg;
278*4882a593Smuzhiyun 	u32 dc_det_level;
279*4882a593Smuzhiyun 	int dc_det_pin;
280*4882a593Smuzhiyun 	bool support_dc_det;
281*4882a593Smuzhiyun 	int virtual_power;
282*4882a593Smuzhiyun 	int sample_res;
283*4882a593Smuzhiyun 	int otg5v_suspend_enable;
284*4882a593Smuzhiyun 	bool extcon;
285*4882a593Smuzhiyun 	int gate_function_disable;
286*4882a593Smuzhiyun };
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun struct rk817_charger {
289*4882a593Smuzhiyun 	struct i2c_client *client;
290*4882a593Smuzhiyun 	struct platform_device *pdev;
291*4882a593Smuzhiyun 	struct device *dev;
292*4882a593Smuzhiyun 	struct rk808 *rk817;
293*4882a593Smuzhiyun 	struct regmap *regmap;
294*4882a593Smuzhiyun 	struct regmap_field *rmap_fields[F_MAX_FIELDS];
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	struct power_supply *ac_psy;
297*4882a593Smuzhiyun 	struct power_supply *usb_psy;
298*4882a593Smuzhiyun 	struct extcon_dev *cable_edev;
299*4882a593Smuzhiyun 	struct charger_platform_data *pdata;
300*4882a593Smuzhiyun 	struct workqueue_struct *usb_charger_wq;
301*4882a593Smuzhiyun 	struct workqueue_struct *dc_charger_wq;
302*4882a593Smuzhiyun 	struct delayed_work dc_work;
303*4882a593Smuzhiyun 	struct delayed_work usb_work;
304*4882a593Smuzhiyun 	struct delayed_work host_work;
305*4882a593Smuzhiyun 	struct delayed_work discnt_work;
306*4882a593Smuzhiyun 	struct delayed_work irq_work;
307*4882a593Smuzhiyun 	struct notifier_block bc_nb;
308*4882a593Smuzhiyun 	struct notifier_block cable_cg_nb;
309*4882a593Smuzhiyun 	struct notifier_block cable_host_nb;
310*4882a593Smuzhiyun 	struct notifier_block cable_discnt_nb;
311*4882a593Smuzhiyun 	unsigned int bc_event;
312*4882a593Smuzhiyun 	enum charger_t usb_charger;
313*4882a593Smuzhiyun 	enum charger_t dc_charger;
314*4882a593Smuzhiyun 	struct regulator *otg5v_rdev;
315*4882a593Smuzhiyun 	u8 ac_in;
316*4882a593Smuzhiyun 	u8 usb_in;
317*4882a593Smuzhiyun 	u8 otg_in;
318*4882a593Smuzhiyun 	u8 dc_in;
319*4882a593Smuzhiyun 	u8 prop_status;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	u32 max_input_current;
322*4882a593Smuzhiyun 	u32 min_input_voltage;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	u32 max_chrg_current;
325*4882a593Smuzhiyun 	u32 max_chrg_voltage;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	u32 chrg_finish_cur;
328*4882a593Smuzhiyun 	u32 chrg_term_mode;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	u8 res_div;
331*4882a593Smuzhiyun 	u8 otg_slp_state;
332*4882a593Smuzhiyun 	u8 plugin_trigger;
333*4882a593Smuzhiyun 	u8 plugout_trigger;
334*4882a593Smuzhiyun 	int plugin_irq;
335*4882a593Smuzhiyun 	int plugout_irq;
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun static enum power_supply_property rk817_ac_props[] = {
339*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ONLINE,
340*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_STATUS,
341*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
342*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_MAX,
343*4882a593Smuzhiyun };
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun static enum power_supply_property rk817_usb_props[] = {
346*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ONLINE,
347*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_STATUS,
348*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
349*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_MAX,
350*4882a593Smuzhiyun };
351*4882a593Smuzhiyun 
rk817_charge_ac_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)352*4882a593Smuzhiyun static int rk817_charge_ac_get_property(struct power_supply *psy,
353*4882a593Smuzhiyun 					enum power_supply_property psp,
354*4882a593Smuzhiyun 					union power_supply_propval *val)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	struct rk817_charger *charge = power_supply_get_drvdata(psy);
357*4882a593Smuzhiyun 	int ret = 0;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	switch (psp) {
360*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ONLINE:
361*4882a593Smuzhiyun 		if (charge->pdata->virtual_power)
362*4882a593Smuzhiyun 			val->intval = 1;
363*4882a593Smuzhiyun 		else
364*4882a593Smuzhiyun 			val->intval = (charge->ac_in | charge->dc_in);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 		DBG("ac report online: %d\n", val->intval);
367*4882a593Smuzhiyun 		break;
368*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
369*4882a593Smuzhiyun 		if (charge->pdata->virtual_power)
370*4882a593Smuzhiyun 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
371*4882a593Smuzhiyun 		else
372*4882a593Smuzhiyun 			val->intval = charge->prop_status;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		DBG("report prop: %d\n", val->intval);
375*4882a593Smuzhiyun 		break;
376*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
377*4882a593Smuzhiyun 		val->intval = charge->max_chrg_voltage * 1000;	/* uV */
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_MAX:
380*4882a593Smuzhiyun 		val->intval = charge->max_chrg_current * 1000;	/* uA */
381*4882a593Smuzhiyun 		break;
382*4882a593Smuzhiyun 	default:
383*4882a593Smuzhiyun 		ret = -EINVAL;
384*4882a593Smuzhiyun 		break;
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	return ret;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
rk817_charge_usb_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)390*4882a593Smuzhiyun static int rk817_charge_usb_get_property(struct power_supply *psy,
391*4882a593Smuzhiyun 					 enum power_supply_property psp,
392*4882a593Smuzhiyun 					 union power_supply_propval *val)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	struct rk817_charger *charge = power_supply_get_drvdata(psy);
395*4882a593Smuzhiyun 	int ret = 0;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	switch (psp) {
398*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ONLINE:
399*4882a593Smuzhiyun 		if (charge->pdata->virtual_power)
400*4882a593Smuzhiyun 			val->intval = 1;
401*4882a593Smuzhiyun 		else
402*4882a593Smuzhiyun 			val->intval = charge->usb_in;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 		DBG("usb report online: %d\n", val->intval);
405*4882a593Smuzhiyun 		break;
406*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
407*4882a593Smuzhiyun 		if (charge->pdata->virtual_power)
408*4882a593Smuzhiyun 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
409*4882a593Smuzhiyun 		else
410*4882a593Smuzhiyun 			val->intval = charge->prop_status;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 		DBG("report prop: %d\n", val->intval);
413*4882a593Smuzhiyun 		break;
414*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
415*4882a593Smuzhiyun 		val->intval = charge->max_chrg_voltage;
416*4882a593Smuzhiyun 		break;
417*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_MAX:
418*4882a593Smuzhiyun 		val->intval = charge->max_chrg_current;
419*4882a593Smuzhiyun 		break;
420*4882a593Smuzhiyun 	default:
421*4882a593Smuzhiyun 		ret = -EINVAL;
422*4882a593Smuzhiyun 		break;
423*4882a593Smuzhiyun 	}
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	return ret;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static const struct power_supply_desc rk817_ac_desc = {
429*4882a593Smuzhiyun 	.name		= "ac",
430*4882a593Smuzhiyun 	.type		= POWER_SUPPLY_TYPE_MAINS,
431*4882a593Smuzhiyun 	.properties	= rk817_ac_props,
432*4882a593Smuzhiyun 	.num_properties	= ARRAY_SIZE(rk817_ac_props),
433*4882a593Smuzhiyun 	.get_property	= rk817_charge_ac_get_property,
434*4882a593Smuzhiyun };
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun static const struct power_supply_desc rk817_usb_desc = {
437*4882a593Smuzhiyun 	.name		= "usb",
438*4882a593Smuzhiyun 	.type		= POWER_SUPPLY_TYPE_USB,
439*4882a593Smuzhiyun 	.properties	= rk817_usb_props,
440*4882a593Smuzhiyun 	.num_properties	= ARRAY_SIZE(rk817_usb_props),
441*4882a593Smuzhiyun 	.get_property	= rk817_charge_usb_get_property,
442*4882a593Smuzhiyun };
443*4882a593Smuzhiyun 
rk817_charge_init_power_supply(struct rk817_charger * charge)444*4882a593Smuzhiyun static int rk817_charge_init_power_supply(struct rk817_charger *charge)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	struct power_supply_config psy_cfg = { .drv_data = charge, };
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	charge->usb_psy = devm_power_supply_register(charge->dev,
449*4882a593Smuzhiyun 						     &rk817_usb_desc,
450*4882a593Smuzhiyun 						     &psy_cfg);
451*4882a593Smuzhiyun 	if (IS_ERR(charge->usb_psy)) {
452*4882a593Smuzhiyun 		dev_err(charge->dev, "register usb power supply fail\n");
453*4882a593Smuzhiyun 		return PTR_ERR(charge->usb_psy);
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	charge->ac_psy = devm_power_supply_register(charge->dev, &rk817_ac_desc,
457*4882a593Smuzhiyun 						&psy_cfg);
458*4882a593Smuzhiyun 	if (IS_ERR(charge->ac_psy)) {
459*4882a593Smuzhiyun 		dev_err(charge->dev, "register ac power supply fail\n");
460*4882a593Smuzhiyun 		return PTR_ERR(charge->ac_psy);
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	return 0;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun 
rk817_charge_field_read(struct rk817_charger * charge,enum rk817_charge_fields field_id)466*4882a593Smuzhiyun static int rk817_charge_field_read(struct rk817_charger *charge,
467*4882a593Smuzhiyun 				   enum rk817_charge_fields field_id)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	int ret;
470*4882a593Smuzhiyun 	int val;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	ret = regmap_field_read(charge->rmap_fields[field_id], &val);
473*4882a593Smuzhiyun 	if (ret < 0)
474*4882a593Smuzhiyun 		return ret;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	return val;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
rk817_charge_field_write(struct rk817_charger * charge,enum rk817_charge_fields field_id,unsigned int val)479*4882a593Smuzhiyun static int rk817_charge_field_write(struct rk817_charger *charge,
480*4882a593Smuzhiyun 				    enum rk817_charge_fields field_id,
481*4882a593Smuzhiyun 				    unsigned int val)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun 	return regmap_field_write(charge->rmap_fields[field_id], val);
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun 
rk817_charge_get_otg_state(struct rk817_charger * charge)486*4882a593Smuzhiyun static int rk817_charge_get_otg_state(struct rk817_charger *charge)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun 	return regulator_is_enabled(charge->otg5v_rdev);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
rk817_charge_boost_disable(struct rk817_charger * charge)491*4882a593Smuzhiyun static void rk817_charge_boost_disable(struct rk817_charger *charge)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	rk817_charge_field_write(charge, BOOST_EN, RK817_BOOST_DISABLE);
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun 
rk817_charge_boost_enable(struct rk817_charger * charge)496*4882a593Smuzhiyun static void rk817_charge_boost_enable(struct rk817_charger *charge)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	rk817_charge_field_write(charge, BOOST_EN, RK817_BOOST_ENABLE);
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
rk817_charge_otg_disable(struct rk817_charger * charge)501*4882a593Smuzhiyun static void rk817_charge_otg_disable(struct rk817_charger *charge)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	int ret;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	ret = regulator_disable(charge->otg5v_rdev);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	if (ret) {
508*4882a593Smuzhiyun 		DBG("disable otg5v failed:%d\n", ret);
509*4882a593Smuzhiyun 		return;
510*4882a593Smuzhiyun 	}
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	return;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
rk817_charge_otg_enable(struct rk817_charger * charge)515*4882a593Smuzhiyun static void rk817_charge_otg_enable(struct rk817_charger *charge)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	int ret;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	ret = regulator_enable(charge->otg5v_rdev);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (ret) {
522*4882a593Smuzhiyun 		DBG("enable otg5v failed:%d\n", ret);
523*4882a593Smuzhiyun 		return;
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	return;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
rk817_charge_get_otg_slp_state(struct rk817_charger * charge)530*4882a593Smuzhiyun static int rk817_charge_get_otg_slp_state(struct rk817_charger *charge)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun 	return (rk817_charge_field_read(charge, OTG_SLP_EN) & OTG_SLP_ENABLE);
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
rk817_charge_otg_slp_disable(struct rk817_charger * charge)535*4882a593Smuzhiyun static void rk817_charge_otg_slp_disable(struct rk817_charger *charge)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	rk817_charge_field_write(charge, OTG_SLP_EN, OTG_SLP_DISABLE);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
rk817_charge_otg_slp_enable(struct rk817_charger * charge)540*4882a593Smuzhiyun static void rk817_charge_otg_slp_enable(struct rk817_charger *charge)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun 	rk817_charge_field_write(charge, OTG_SLP_EN, OTG_SLP_ENABLE);
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun #endif
545*4882a593Smuzhiyun 
rk817_charge_get_charge_state(struct rk817_charger * charge)546*4882a593Smuzhiyun static int rk817_charge_get_charge_state(struct rk817_charger *charge)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	return rk817_charge_field_read(charge, CHRG_EN);
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
rk817_charge_enable_charge(struct rk817_charger * charge)551*4882a593Smuzhiyun static void rk817_charge_enable_charge(struct rk817_charger *charge)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun 	rk817_charge_field_write(charge, CHRG_EN, ENABLE);
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
rk817_charge_usb_to_sys_enable(struct rk817_charger * charge)556*4882a593Smuzhiyun static void rk817_charge_usb_to_sys_enable(struct rk817_charger *charge)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	rk817_charge_field_write(charge, USB_SYS_EN, ENABLE);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
rk817_charge_sys_can_sd_disable(struct rk817_charger * charge)561*4882a593Smuzhiyun static void rk817_charge_sys_can_sd_disable(struct rk817_charger *charge)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	rk817_charge_field_write(charge, SYS_CAN_SD, DISABLE);
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun 
rk817_charge_get_charge_status(struct rk817_charger * charge)566*4882a593Smuzhiyun static int rk817_charge_get_charge_status(struct rk817_charger *charge)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	int status;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	status = rk817_charge_field_read(charge, CHG_STS);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	switch (status) {
573*4882a593Smuzhiyun 	case CHRG_OFF:
574*4882a593Smuzhiyun 		DBG("charge off...\n");
575*4882a593Smuzhiyun 		break;
576*4882a593Smuzhiyun 	case DEAD_CHRG:
577*4882a593Smuzhiyun 		DBG("dead charge...\n");
578*4882a593Smuzhiyun 		break;
579*4882a593Smuzhiyun 	case TRICKLE_CHRG:
580*4882a593Smuzhiyun 		DBG("trickle charge...\n");
581*4882a593Smuzhiyun 		break;
582*4882a593Smuzhiyun 	case CC_OR_CV_CHRG:
583*4882a593Smuzhiyun 		DBG("CC or CV charge...\n");
584*4882a593Smuzhiyun 		break;
585*4882a593Smuzhiyun 	case CHRG_TERM:
586*4882a593Smuzhiyun 		DBG("charge TERM...\n");
587*4882a593Smuzhiyun 		break;
588*4882a593Smuzhiyun 	case USB_OVER_VOL:
589*4882a593Smuzhiyun 		DBG("USB over voltage...\n");
590*4882a593Smuzhiyun 		break;
591*4882a593Smuzhiyun 	case BAT_TMP_ERR:
592*4882a593Smuzhiyun 		DBG("battery temperature error...\n");
593*4882a593Smuzhiyun 		break;
594*4882a593Smuzhiyun 	case BAT_TIM_ERR:
595*4882a593Smuzhiyun 		DBG("battery timer error..\n");
596*4882a593Smuzhiyun 		break;
597*4882a593Smuzhiyun 	default:
598*4882a593Smuzhiyun 		break;
599*4882a593Smuzhiyun 	}
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	return status;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
rk817_charge_get_plug_in_status(struct rk817_charger * charge)604*4882a593Smuzhiyun static int rk817_charge_get_plug_in_status(struct rk817_charger *charge)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	return rk817_charge_field_read(charge, PLUG_IN_STS);
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
rk817_charge_set_charge_clock(struct rk817_charger * charge,enum charge_clk clock)609*4882a593Smuzhiyun static void rk817_charge_set_charge_clock(struct rk817_charger *charge,
610*4882a593Smuzhiyun 					  enum charge_clk clock)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	rk817_charge_field_write(charge, CHRG_CLK_SEL, clock);
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
is_battery_exist(struct rk817_charger * charge)615*4882a593Smuzhiyun static int is_battery_exist(struct rk817_charger *charge)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	return rk817_charge_field_read(charge, BAT_EXS);
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun 
rk817_charge_set_chrg_voltage(struct rk817_charger * charge,int chrg_vol)620*4882a593Smuzhiyun static void rk817_charge_set_chrg_voltage(struct rk817_charger *charge,
621*4882a593Smuzhiyun 					  int chrg_vol)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	int voltage;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (chrg_vol < 4100 || chrg_vol > 4500) {
626*4882a593Smuzhiyun 		dev_err(charge->dev, "the charge voltage is error!\n");
627*4882a593Smuzhiyun 	} else {
628*4882a593Smuzhiyun 		voltage = (chrg_vol - 4100) / 50;
629*4882a593Smuzhiyun 		rk817_charge_field_write(charge,
630*4882a593Smuzhiyun 					 CHRG_VOL_SEL,
631*4882a593Smuzhiyun 					 CHRG_VOL_4100MV + voltage);
632*4882a593Smuzhiyun 	}
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
rk817_charge_set_chrg_current(struct rk817_charger * charge,int chrg_current)635*4882a593Smuzhiyun static void rk817_charge_set_chrg_current(struct rk817_charger *charge,
636*4882a593Smuzhiyun 					  int chrg_current)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun 	if (chrg_current < 500 || chrg_current > 3500)
639*4882a593Smuzhiyun 		dev_err(charge->dev, "the charge current is error!\n");
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	if (chrg_current < 1000)
642*4882a593Smuzhiyun 		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_500MA);
643*4882a593Smuzhiyun 	else if (chrg_current < 1500)
644*4882a593Smuzhiyun 		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_1000MA);
645*4882a593Smuzhiyun 	else if (chrg_current < 2000)
646*4882a593Smuzhiyun 		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_1500MA);
647*4882a593Smuzhiyun 	else if (chrg_current < 2500)
648*4882a593Smuzhiyun 		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_2000MA);
649*4882a593Smuzhiyun 	else if (chrg_current < 3000)
650*4882a593Smuzhiyun 		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_2500MA);
651*4882a593Smuzhiyun 	else if (chrg_current < 3500)
652*4882a593Smuzhiyun 		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_3000MA);
653*4882a593Smuzhiyun 	else
654*4882a593Smuzhiyun 		rk817_charge_field_write(charge, CHRG_CUR_SEL, CHRG_CUR_3500MA);
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun 
rk817_charge_vlimit_enable(struct rk817_charger * charge)657*4882a593Smuzhiyun static void rk817_charge_vlimit_enable(struct rk817_charger *charge)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun 	rk817_charge_field_write(charge, USB_VLIM_EN, ENABLE);
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun 
rk817_charge_set_input_voltage(struct rk817_charger * charge,int input_voltage)662*4882a593Smuzhiyun static void rk817_charge_set_input_voltage(struct rk817_charger *charge,
663*4882a593Smuzhiyun 					   int input_voltage)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	int voltage;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	if (input_voltage < 4000)
668*4882a593Smuzhiyun 		dev_err(charge->dev, "the input voltage is error.\n");
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	voltage = INPUT_VOL_4000MV + (input_voltage - 4000) / 100;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	rk817_charge_field_write(charge, USB_VLIM_SEL, voltage);
673*4882a593Smuzhiyun 	rk817_charge_vlimit_enable(charge);
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun 
rk817_charge_ilimit_enable(struct rk817_charger * charge)676*4882a593Smuzhiyun static void rk817_charge_ilimit_enable(struct rk817_charger *charge)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun 	rk817_charge_field_write(charge, USB_ILIM_EN, ENABLE);
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
rk817_charge_set_input_current(struct rk817_charger * charge,int input_current)681*4882a593Smuzhiyun static void rk817_charge_set_input_current(struct rk817_charger *charge,
682*4882a593Smuzhiyun 					   int input_current)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	if (input_current < 80 || input_current > 3000)
685*4882a593Smuzhiyun 		dev_err(charge->dev, "the input current is error.\n");
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	if (input_current < 450)
688*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
689*4882a593Smuzhiyun 					 INPUT_CUR_80MA);
690*4882a593Smuzhiyun 	else if (input_current < 850)
691*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
692*4882a593Smuzhiyun 					 INPUT_CUR_450MA);
693*4882a593Smuzhiyun 	else if (input_current < 1500)
694*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
695*4882a593Smuzhiyun 					 INPUT_CUR_850MA);
696*4882a593Smuzhiyun 	else if (input_current < 1750)
697*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
698*4882a593Smuzhiyun 					 INPUT_CUR_1500MA);
699*4882a593Smuzhiyun 	else if (input_current < 2000)
700*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
701*4882a593Smuzhiyun 					 INPUT_CUR_1750MA);
702*4882a593Smuzhiyun 	else if (input_current < 2500)
703*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
704*4882a593Smuzhiyun 					 INPUT_CUR_2000MA);
705*4882a593Smuzhiyun 	else if (input_current < 3000)
706*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
707*4882a593Smuzhiyun 					 INPUT_CUR_2500MA);
708*4882a593Smuzhiyun 	else
709*4882a593Smuzhiyun 		rk817_charge_field_write(charge, USB_ILIM_SEL,
710*4882a593Smuzhiyun 					 INPUT_CUR_3000MA);
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	rk817_charge_ilimit_enable(charge);
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
rk817_charge_set_chrg_term_mod(struct rk817_charger * charge,int mode)715*4882a593Smuzhiyun static void rk817_charge_set_chrg_term_mod(struct rk817_charger *charge,
716*4882a593Smuzhiyun 					   int mode)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun 	rk817_charge_field_write(charge, CHRG_TERM_ANA_DIG, mode);
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun 
rk817_charge_set_term_current_analog(struct rk817_charger * charge,int chrg_current)721*4882a593Smuzhiyun static void rk817_charge_set_term_current_analog(struct rk817_charger *charge,
722*4882a593Smuzhiyun 						 int chrg_current)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	int value;
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	if (chrg_current < 200)
727*4882a593Smuzhiyun 		value = CHRG_TERM_150MA;
728*4882a593Smuzhiyun 	else if (chrg_current < 300)
729*4882a593Smuzhiyun 		value = CHRG_TERM_200MA;
730*4882a593Smuzhiyun 	else if (chrg_current < 400)
731*4882a593Smuzhiyun 		value = CHRG_TERM_300MA;
732*4882a593Smuzhiyun 	else
733*4882a593Smuzhiyun 		value = CHRG_TERM_400MA;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	rk817_charge_field_write(charge,
736*4882a593Smuzhiyun 				 CHRG_TERM_ANA_SEL,
737*4882a593Smuzhiyun 				 value);
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun 
rk817_charge_set_term_current_digital(struct rk817_charger * charge,int chrg_current)740*4882a593Smuzhiyun static void rk817_charge_set_term_current_digital(struct rk817_charger *charge,
741*4882a593Smuzhiyun 						  int chrg_current)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun 	int value;
744*4882a593Smuzhiyun 	u8 current_adc;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	value = CURRENT_TO_ADC(chrg_current, charge->res_div);
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	value &= (0xff << 5);
749*4882a593Smuzhiyun 	current_adc = value >> 5;
750*4882a593Smuzhiyun 	rk817_charge_field_write(charge, CHRG_TERM_DIG, current_adc);
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun 
rk817_charge_set_chrg_finish_condition(struct rk817_charger * charge)753*4882a593Smuzhiyun static void rk817_charge_set_chrg_finish_condition(struct rk817_charger *charge)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	if (charge->chrg_term_mode == CHRG_ANALOG)
756*4882a593Smuzhiyun 		rk817_charge_set_term_current_analog(charge,
757*4882a593Smuzhiyun 						     charge->chrg_finish_cur);
758*4882a593Smuzhiyun 	else
759*4882a593Smuzhiyun 		rk817_charge_set_term_current_digital(charge,
760*4882a593Smuzhiyun 						      charge->chrg_finish_cur);
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	rk817_charge_set_chrg_term_mod(charge, charge->chrg_term_mode);
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun 
rk817_charge_online(struct rk817_charger * charge)765*4882a593Smuzhiyun static int rk817_charge_online(struct rk817_charger *charge)
766*4882a593Smuzhiyun {
767*4882a593Smuzhiyun 	return (charge->ac_in | charge->usb_in | charge->dc_in);
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun 
rk817_charge_get_dsoc(struct rk817_charger * charge)770*4882a593Smuzhiyun static int rk817_charge_get_dsoc(struct rk817_charger *charge)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun 	int soc_save;
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	soc_save = rk817_charge_field_read(charge, SOC_REG0);
775*4882a593Smuzhiyun 	soc_save |= (rk817_charge_field_read(charge, SOC_REG1) << 8);
776*4882a593Smuzhiyun 	soc_save |= (rk817_charge_field_read(charge, SOC_REG2) << 16);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	return soc_save / 1000;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun 
rk817_charge_set_otg_in(struct rk817_charger * charge,int online)781*4882a593Smuzhiyun static void rk817_charge_set_otg_in(struct rk817_charger *charge, int online)
782*4882a593Smuzhiyun {
783*4882a593Smuzhiyun 	charge->otg_in = online;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun 
rk817_charge_set_chrg_param(struct rk817_charger * charge,enum charger_t charger)786*4882a593Smuzhiyun static void rk817_charge_set_chrg_param(struct rk817_charger *charge,
787*4882a593Smuzhiyun 					enum charger_t charger)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun 	switch (charger) {
790*4882a593Smuzhiyun 	case USB_TYPE_NONE_CHARGER:
791*4882a593Smuzhiyun 		charge->usb_in = 0;
792*4882a593Smuzhiyun 		charge->ac_in = 0;
793*4882a593Smuzhiyun 		if (charge->dc_in == 0) {
794*4882a593Smuzhiyun 			charge->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
795*4882a593Smuzhiyun 			rk817_charge_set_input_current(charge, INPUT_450MA);
796*4882a593Smuzhiyun 		}
797*4882a593Smuzhiyun 		power_supply_changed(charge->usb_psy);
798*4882a593Smuzhiyun 		power_supply_changed(charge->ac_psy);
799*4882a593Smuzhiyun 		break;
800*4882a593Smuzhiyun 	case USB_TYPE_USB_CHARGER:
801*4882a593Smuzhiyun 		charge->usb_in = 1;
802*4882a593Smuzhiyun 		charge->ac_in = 0;
803*4882a593Smuzhiyun 		charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
804*4882a593Smuzhiyun 		if (charge->dc_in == 0)
805*4882a593Smuzhiyun 			rk817_charge_set_input_current(charge, INPUT_450MA);
806*4882a593Smuzhiyun 		power_supply_changed(charge->usb_psy);
807*4882a593Smuzhiyun 		power_supply_changed(charge->ac_psy);
808*4882a593Smuzhiyun 		break;
809*4882a593Smuzhiyun 	case USB_TYPE_AC_CHARGER:
810*4882a593Smuzhiyun 	case USB_TYPE_CDP_CHARGER:
811*4882a593Smuzhiyun 		charge->ac_in = 1;
812*4882a593Smuzhiyun 		charge->usb_in = 0;
813*4882a593Smuzhiyun 		charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
814*4882a593Smuzhiyun 		if (charger == USB_TYPE_AC_CHARGER)
815*4882a593Smuzhiyun 			rk817_charge_set_input_current(charge,
816*4882a593Smuzhiyun 						       charge->max_input_current);
817*4882a593Smuzhiyun 		else
818*4882a593Smuzhiyun 			rk817_charge_set_input_current(charge,
819*4882a593Smuzhiyun 						       INPUT_1500MA);
820*4882a593Smuzhiyun 		power_supply_changed(charge->usb_psy);
821*4882a593Smuzhiyun 		power_supply_changed(charge->ac_psy);
822*4882a593Smuzhiyun 		break;
823*4882a593Smuzhiyun 	case DC_TYPE_DC_CHARGER:
824*4882a593Smuzhiyun 		charge->dc_in = 1;
825*4882a593Smuzhiyun 		charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
826*4882a593Smuzhiyun 		rk817_charge_set_input_current(charge,
827*4882a593Smuzhiyun 					       charge->max_input_current);
828*4882a593Smuzhiyun 		power_supply_changed(charge->usb_psy);
829*4882a593Smuzhiyun 		power_supply_changed(charge->ac_psy);
830*4882a593Smuzhiyun 		break;
831*4882a593Smuzhiyun 	case DC_TYPE_NONE_CHARGER:
832*4882a593Smuzhiyun 		charge->dc_in = 0;
833*4882a593Smuzhiyun 		if (!rk817_charge_get_plug_in_status(charge)) {
834*4882a593Smuzhiyun 			charge->ac_in = 0;
835*4882a593Smuzhiyun 			charge->usb_in = 0;
836*4882a593Smuzhiyun 			charge->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
837*4882a593Smuzhiyun 			rk817_charge_set_input_current(charge, INPUT_450MA);
838*4882a593Smuzhiyun 		} else if (charge->usb_in) {
839*4882a593Smuzhiyun 			rk817_charge_set_input_current(charge, INPUT_450MA);
840*4882a593Smuzhiyun 			charge->prop_status = POWER_SUPPLY_STATUS_CHARGING;
841*4882a593Smuzhiyun 		}
842*4882a593Smuzhiyun 		power_supply_changed(charge->usb_psy);
843*4882a593Smuzhiyun 		power_supply_changed(charge->ac_psy);
844*4882a593Smuzhiyun 		break;
845*4882a593Smuzhiyun 	default:
846*4882a593Smuzhiyun 		charge->prop_status = POWER_SUPPLY_STATUS_DISCHARGING;
847*4882a593Smuzhiyun 		rk817_charge_set_input_current(charge, INPUT_450MA);
848*4882a593Smuzhiyun 		break;
849*4882a593Smuzhiyun 	}
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	if (rk817_charge_online(charge) && rk817_charge_get_dsoc(charge) == 100)
852*4882a593Smuzhiyun 		charge->prop_status = POWER_SUPPLY_STATUS_FULL;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun 
rk817_charge_set_otg_state(struct rk817_charger * charge,int state)855*4882a593Smuzhiyun static void rk817_charge_set_otg_state(struct rk817_charger *charge, int state)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun 	switch (state) {
858*4882a593Smuzhiyun 	case USB_OTG_POWER_ON:
859*4882a593Smuzhiyun 		if (charge->otg_in) {
860*4882a593Smuzhiyun 			DBG("otg5v is on yet, ignore..\n");
861*4882a593Smuzhiyun 		} else {
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 			if (!rk817_charge_get_otg_state(charge)) {
864*4882a593Smuzhiyun 				rk817_charge_otg_enable(charge);
865*4882a593Smuzhiyun 				if (!rk817_charge_get_otg_state(charge)) {
866*4882a593Smuzhiyun 					DBG("enable otg5v failed\n");
867*4882a593Smuzhiyun 					return;
868*4882a593Smuzhiyun 				}
869*4882a593Smuzhiyun 			}
870*4882a593Smuzhiyun 			disable_irq(charge->plugin_irq);
871*4882a593Smuzhiyun 			disable_irq(charge->plugout_irq);
872*4882a593Smuzhiyun 			DBG("enable otg5v\n");
873*4882a593Smuzhiyun 		}
874*4882a593Smuzhiyun 		break;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	case USB_OTG_POWER_OFF:
877*4882a593Smuzhiyun 		if (!charge->otg_in) {
878*4882a593Smuzhiyun 			DBG("otg5v is off yet, ignore..\n");
879*4882a593Smuzhiyun 		} else {
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 			if (rk817_charge_get_otg_state(charge)) {
882*4882a593Smuzhiyun 				rk817_charge_otg_disable(charge);
883*4882a593Smuzhiyun 				if (rk817_charge_get_otg_state(charge)) {
884*4882a593Smuzhiyun 					DBG("disable otg5v failed\n");
885*4882a593Smuzhiyun 					return;
886*4882a593Smuzhiyun 				}
887*4882a593Smuzhiyun 			}
888*4882a593Smuzhiyun 			enable_irq(charge->plugin_irq);
889*4882a593Smuzhiyun 			enable_irq(charge->plugout_irq);
890*4882a593Smuzhiyun 			DBG("disable otg5v\n");
891*4882a593Smuzhiyun 		}
892*4882a593Smuzhiyun 		break;
893*4882a593Smuzhiyun 	default:
894*4882a593Smuzhiyun 		dev_err(charge->dev, "error otg type\n");
895*4882a593Smuzhiyun 		break;
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun 
rk817_charge_dc_det_isr(int irq,void * charger)899*4882a593Smuzhiyun static irqreturn_t rk817_charge_dc_det_isr(int irq, void *charger)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun 	struct rk817_charger *charge = (struct rk817_charger *)charger;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	if (gpio_get_value(charge->pdata->dc_det_pin))
904*4882a593Smuzhiyun 		irq_set_irq_type(irq, IRQF_TRIGGER_LOW);
905*4882a593Smuzhiyun 	else
906*4882a593Smuzhiyun 		irq_set_irq_type(irq, IRQF_TRIGGER_HIGH);
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 	queue_delayed_work(charge->dc_charger_wq, &charge->dc_work,
909*4882a593Smuzhiyun 			   msecs_to_jiffies(10));
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	return IRQ_HANDLED;
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun 
rk817_charge_get_dc_state(struct rk817_charger * charge)914*4882a593Smuzhiyun static enum charger_t rk817_charge_get_dc_state(struct rk817_charger *charge)
915*4882a593Smuzhiyun {
916*4882a593Smuzhiyun 	int level;
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	if (!gpio_is_valid(charge->pdata->dc_det_pin))
919*4882a593Smuzhiyun 		return DC_TYPE_NONE_CHARGER;
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	level = gpio_get_value(charge->pdata->dc_det_pin);
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	return (level == charge->pdata->dc_det_level) ?
924*4882a593Smuzhiyun 		DC_TYPE_DC_CHARGER : DC_TYPE_NONE_CHARGER;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun 
rk817_charge_dc_det_worker(struct work_struct * work)927*4882a593Smuzhiyun static void rk817_charge_dc_det_worker(struct work_struct *work)
928*4882a593Smuzhiyun {
929*4882a593Smuzhiyun 	enum charger_t charger;
930*4882a593Smuzhiyun 	struct rk817_charger *charge = container_of(work,
931*4882a593Smuzhiyun 			struct rk817_charger, dc_work.work);
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	charger = rk817_charge_get_dc_state(charge);
934*4882a593Smuzhiyun 	if (charger == DC_TYPE_DC_CHARGER) {
935*4882a593Smuzhiyun 		DBG("detect dc charger in..\n");
936*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, DC_TYPE_DC_CHARGER);
937*4882a593Smuzhiyun 		/* check otg supply */
938*4882a593Smuzhiyun 		if (charge->otg_in && charge->pdata->power_dc2otg) {
939*4882a593Smuzhiyun 			DBG("otg power from dc adapter\n");
940*4882a593Smuzhiyun 			rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
941*4882a593Smuzhiyun 		}
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 		rk817_charge_boost_disable(charge);
944*4882a593Smuzhiyun 	} else {
945*4882a593Smuzhiyun 		DBG("detect dc charger out..\n");
946*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, DC_TYPE_NONE_CHARGER);
947*4882a593Smuzhiyun 		rk817_charge_boost_enable(charge);
948*4882a593Smuzhiyun 		/* check otg supply, power on anyway */
949*4882a593Smuzhiyun 		if (charge->otg_in)
950*4882a593Smuzhiyun 			rk817_charge_set_otg_state(charge, USB_OTG_POWER_ON);
951*4882a593Smuzhiyun 	}
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun 
rk817_charge_init_dc(struct rk817_charger * charge)954*4882a593Smuzhiyun static int rk817_charge_init_dc(struct rk817_charger *charge)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun 	int ret, level;
957*4882a593Smuzhiyun 	unsigned long irq_flags;
958*4882a593Smuzhiyun 	unsigned int dc_det_irq;
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	charge->dc_charger_wq = alloc_ordered_workqueue("%s",
961*4882a593Smuzhiyun 				WQ_MEM_RECLAIM | WQ_FREEZABLE,
962*4882a593Smuzhiyun 				"rk817-dc-wq");
963*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&charge->dc_work, rk817_charge_dc_det_worker);
964*4882a593Smuzhiyun 	charge->dc_charger = DC_TYPE_NONE_CHARGER;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	if (!charge->pdata->support_dc_det)
967*4882a593Smuzhiyun 		return 0;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	ret = devm_gpio_request(charge->dev,
970*4882a593Smuzhiyun 				charge->pdata->dc_det_pin,
971*4882a593Smuzhiyun 				"rk817_dc_det");
972*4882a593Smuzhiyun 	if (ret < 0) {
973*4882a593Smuzhiyun 		dev_err(charge->dev, "failed to request gpio %d\n",
974*4882a593Smuzhiyun 			charge->pdata->dc_det_pin);
975*4882a593Smuzhiyun 		return ret;
976*4882a593Smuzhiyun 	}
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	ret = gpio_direction_input(charge->pdata->dc_det_pin);
979*4882a593Smuzhiyun 	if (ret) {
980*4882a593Smuzhiyun 		dev_err(charge->dev, "failed to set gpio input\n");
981*4882a593Smuzhiyun 		return ret;
982*4882a593Smuzhiyun 	}
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	level = gpio_get_value(charge->pdata->dc_det_pin);
985*4882a593Smuzhiyun 	if (level == charge->pdata->dc_det_level)
986*4882a593Smuzhiyun 		charge->dc_charger = DC_TYPE_DC_CHARGER;
987*4882a593Smuzhiyun 	else
988*4882a593Smuzhiyun 		charge->dc_charger = DC_TYPE_NONE_CHARGER;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	if (level)
991*4882a593Smuzhiyun 		irq_flags = IRQF_TRIGGER_LOW;
992*4882a593Smuzhiyun 	else
993*4882a593Smuzhiyun 		irq_flags = IRQF_TRIGGER_HIGH;
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	dc_det_irq = gpio_to_irq(charge->pdata->dc_det_pin);
996*4882a593Smuzhiyun 	ret = devm_request_irq(charge->dev, dc_det_irq, rk817_charge_dc_det_isr,
997*4882a593Smuzhiyun 			       irq_flags, "rk817_dc_det", charge);
998*4882a593Smuzhiyun 	if (ret != 0) {
999*4882a593Smuzhiyun 		dev_err(charge->dev, "rk817_dc_det_irq request failed!\n");
1000*4882a593Smuzhiyun 		return ret;
1001*4882a593Smuzhiyun 	}
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 	enable_irq_wake(dc_det_irq);
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	if (charge->dc_charger != DC_TYPE_NONE_CHARGER)
1006*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, charge->dc_charger);
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun 	return 0;
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun 
rk817_charge_host_evt_worker(struct work_struct * work)1011*4882a593Smuzhiyun static void rk817_charge_host_evt_worker(struct work_struct *work)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun 	struct rk817_charger *charge = container_of(work,
1014*4882a593Smuzhiyun 			struct rk817_charger, host_work.work);
1015*4882a593Smuzhiyun 	struct extcon_dev *edev = charge->cable_edev;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	/* Determine cable/charger type */
1018*4882a593Smuzhiyun 	if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) {
1019*4882a593Smuzhiyun 		DBG("receive type-c notifier event: OTG ON...\n");
1020*4882a593Smuzhiyun 		if (charge->dc_in && charge->pdata->power_dc2otg) {
1021*4882a593Smuzhiyun 			if (charge->otg_in)
1022*4882a593Smuzhiyun 				rk817_charge_set_otg_state(charge,
1023*4882a593Smuzhiyun 							   USB_OTG_POWER_OFF);
1024*4882a593Smuzhiyun 			DBG("otg power from dc adapter\n");
1025*4882a593Smuzhiyun 		} else {
1026*4882a593Smuzhiyun 			rk817_charge_set_otg_state(charge, USB_OTG_POWER_ON);
1027*4882a593Smuzhiyun 		}
1028*4882a593Smuzhiyun 		rk817_charge_set_otg_in(charge, ONLINE);
1029*4882a593Smuzhiyun 	} else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) {
1030*4882a593Smuzhiyun 		DBG("receive type-c notifier event: OTG OFF...\n");
1031*4882a593Smuzhiyun 		rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
1032*4882a593Smuzhiyun 		rk817_charge_set_otg_in(charge, OFFLINE);
1033*4882a593Smuzhiyun 	}
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun 
rk817_charger_evt_worker(struct work_struct * work)1036*4882a593Smuzhiyun static void rk817_charger_evt_worker(struct work_struct *work)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun 	struct rk817_charger *charge = container_of(work,
1039*4882a593Smuzhiyun 				struct rk817_charger, usb_work.work);
1040*4882a593Smuzhiyun 	struct extcon_dev *edev = charge->cable_edev;
1041*4882a593Smuzhiyun 	enum charger_t charger = USB_TYPE_UNKNOWN_CHARGER;
1042*4882a593Smuzhiyun 	static const char * const event[] = {"UN", "NONE", "USB",
1043*4882a593Smuzhiyun 					     "AC", "CDP1.5A"};
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun 	/* Determine cable/charger type */
1046*4882a593Smuzhiyun 	if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0)
1047*4882a593Smuzhiyun 		charger = USB_TYPE_USB_CHARGER;
1048*4882a593Smuzhiyun 	else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0)
1049*4882a593Smuzhiyun 		charger = USB_TYPE_AC_CHARGER;
1050*4882a593Smuzhiyun 	else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0)
1051*4882a593Smuzhiyun 		charger = USB_TYPE_CDP_CHARGER;
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 	if (charger != USB_TYPE_UNKNOWN_CHARGER) {
1054*4882a593Smuzhiyun 		DBG("receive type-c notifier event: %s...\n",
1055*4882a593Smuzhiyun 		    event[charger]);
1056*4882a593Smuzhiyun 		charge->usb_charger = charger;
1057*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, charger);
1058*4882a593Smuzhiyun 	}
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun 
rk817_charge_discnt_evt_worker(struct work_struct * work)1061*4882a593Smuzhiyun static void rk817_charge_discnt_evt_worker(struct work_struct *work)
1062*4882a593Smuzhiyun {
1063*4882a593Smuzhiyun 	struct rk817_charger *charge = container_of(work,
1064*4882a593Smuzhiyun 			struct rk817_charger, discnt_work.work);
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 	if (extcon_get_state(charge->cable_edev, EXTCON_USB) == 0) {
1067*4882a593Smuzhiyun 		DBG("receive type-c notifier event: DISCNT...\n");
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, USB_TYPE_NONE_CHARGER);
1070*4882a593Smuzhiyun 	}
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun 
rk817_charge_bc_evt_worker(struct work_struct * work)1073*4882a593Smuzhiyun static void rk817_charge_bc_evt_worker(struct work_struct *work)
1074*4882a593Smuzhiyun {
1075*4882a593Smuzhiyun 	struct rk817_charger *charge = container_of(work,
1076*4882a593Smuzhiyun 						    struct rk817_charger,
1077*4882a593Smuzhiyun 						    usb_work.work);
1078*4882a593Smuzhiyun 	static const char * const event_name[] = {"DISCNT", "USB", "AC",
1079*4882a593Smuzhiyun 						  "CDP1.5A", "UNKNOWN",
1080*4882a593Smuzhiyun 						  "OTG ON", "OTG OFF"};
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	switch (charge->bc_event) {
1083*4882a593Smuzhiyun 	case USB_BC_TYPE_DISCNT:
1084*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, USB_TYPE_NONE_CHARGER);
1085*4882a593Smuzhiyun 		break;
1086*4882a593Smuzhiyun 	case USB_BC_TYPE_SDP:
1087*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, USB_TYPE_USB_CHARGER);
1088*4882a593Smuzhiyun 		break;
1089*4882a593Smuzhiyun 	case USB_BC_TYPE_DCP:
1090*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, USB_TYPE_AC_CHARGER);
1091*4882a593Smuzhiyun 		break;
1092*4882a593Smuzhiyun 	case USB_BC_TYPE_CDP:
1093*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, USB_TYPE_CDP_CHARGER);
1094*4882a593Smuzhiyun 		break;
1095*4882a593Smuzhiyun 	case USB_OTG_POWER_ON:
1096*4882a593Smuzhiyun 		if (charge->pdata->power_dc2otg && charge->dc_in)
1097*4882a593Smuzhiyun 			DBG("otg power from dc adapter\n");
1098*4882a593Smuzhiyun 		else
1099*4882a593Smuzhiyun 			rk817_charge_set_otg_state(charge, USB_OTG_POWER_ON);
1100*4882a593Smuzhiyun 		break;
1101*4882a593Smuzhiyun 	case USB_OTG_POWER_OFF:
1102*4882a593Smuzhiyun 		rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
1103*4882a593Smuzhiyun 		break;
1104*4882a593Smuzhiyun 	default:
1105*4882a593Smuzhiyun 		break;
1106*4882a593Smuzhiyun 	}
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	DBG("receive bc notifier event: %s..\n", event_name[charge->bc_event]);
1109*4882a593Smuzhiyun }
1110*4882a593Smuzhiyun 
rk817_charger_evt_notifier(struct notifier_block * nb,unsigned long event,void * ptr)1111*4882a593Smuzhiyun static int rk817_charger_evt_notifier(struct notifier_block *nb,
1112*4882a593Smuzhiyun 				      unsigned long event, void *ptr)
1113*4882a593Smuzhiyun {
1114*4882a593Smuzhiyun 	struct rk817_charger *charge =
1115*4882a593Smuzhiyun 		container_of(nb, struct rk817_charger, cable_cg_nb);
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	queue_delayed_work(charge->usb_charger_wq, &charge->usb_work,
1118*4882a593Smuzhiyun 			   msecs_to_jiffies(10));
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	return NOTIFY_DONE;
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun 
rk817_charge_host_evt_notifier(struct notifier_block * nb,unsigned long event,void * ptr)1123*4882a593Smuzhiyun static int rk817_charge_host_evt_notifier(struct notifier_block *nb,
1124*4882a593Smuzhiyun 					  unsigned long event, void *ptr)
1125*4882a593Smuzhiyun {
1126*4882a593Smuzhiyun 	struct rk817_charger *charge =
1127*4882a593Smuzhiyun 		container_of(nb, struct rk817_charger, cable_host_nb);
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	queue_delayed_work(charge->usb_charger_wq, &charge->host_work,
1130*4882a593Smuzhiyun 			   msecs_to_jiffies(10));
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	return NOTIFY_DONE;
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun 
rk817_charge_discnt_evt_notfier(struct notifier_block * nb,unsigned long event,void * ptr)1135*4882a593Smuzhiyun static int rk817_charge_discnt_evt_notfier(struct notifier_block *nb,
1136*4882a593Smuzhiyun 					   unsigned long event, void *ptr)
1137*4882a593Smuzhiyun {
1138*4882a593Smuzhiyun 	struct rk817_charger *charge =
1139*4882a593Smuzhiyun 		container_of(nb, struct rk817_charger, cable_discnt_nb);
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	queue_delayed_work(charge->usb_charger_wq, &charge->discnt_work,
1142*4882a593Smuzhiyun 			   msecs_to_jiffies(10));
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	return NOTIFY_DONE;
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun 
rk817_charge_bc_evt_notifier(struct notifier_block * nb,unsigned long event,void * ptr)1147*4882a593Smuzhiyun static int rk817_charge_bc_evt_notifier(struct notifier_block *nb,
1148*4882a593Smuzhiyun 					unsigned long event, void *ptr)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun 	struct rk817_charger *charge =
1151*4882a593Smuzhiyun 		container_of(nb, struct rk817_charger, bc_nb);
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	charge->bc_event = event;
1154*4882a593Smuzhiyun 	queue_delayed_work(charge->usb_charger_wq, &charge->usb_work,
1155*4882a593Smuzhiyun 			   msecs_to_jiffies(10));
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	return NOTIFY_DONE;
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun 
rk817_charge_usb_init(struct rk817_charger * charge)1160*4882a593Smuzhiyun static int rk817_charge_usb_init(struct rk817_charger *charge)
1161*4882a593Smuzhiyun {
1162*4882a593Smuzhiyun 	enum charger_t charger;
1163*4882a593Smuzhiyun 	enum bc_port_type bc_type;
1164*4882a593Smuzhiyun 	struct extcon_dev *edev;
1165*4882a593Smuzhiyun 	struct device *dev = charge->dev;
1166*4882a593Smuzhiyun 	int ret;
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	charge->usb_charger_wq = alloc_ordered_workqueue("%s",
1169*4882a593Smuzhiyun 				WQ_MEM_RECLAIM | WQ_FREEZABLE,
1170*4882a593Smuzhiyun 				"rk817-usb-wq");
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	/* type-C */
1173*4882a593Smuzhiyun 	if (charge->pdata->extcon) {
1174*4882a593Smuzhiyun 		edev = extcon_get_edev_by_phandle(dev, 0);
1175*4882a593Smuzhiyun 		if (IS_ERR(edev)) {
1176*4882a593Smuzhiyun 			if (PTR_ERR(edev) != -EPROBE_DEFER)
1177*4882a593Smuzhiyun 				dev_err(dev, "Invalid or missing extcon\n");
1178*4882a593Smuzhiyun 			return PTR_ERR(edev);
1179*4882a593Smuzhiyun 		}
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 		/* Register chargers  */
1182*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&charge->usb_work, rk817_charger_evt_worker);
1183*4882a593Smuzhiyun 		charge->cable_cg_nb.notifier_call = rk817_charger_evt_notifier;
1184*4882a593Smuzhiyun 		ret = extcon_register_notifier(edev, EXTCON_CHG_USB_SDP,
1185*4882a593Smuzhiyun 					       &charge->cable_cg_nb);
1186*4882a593Smuzhiyun 		if (ret < 0) {
1187*4882a593Smuzhiyun 			dev_err(dev, "failed to register notifier for SDP\n");
1188*4882a593Smuzhiyun 			return ret;
1189*4882a593Smuzhiyun 		}
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 		ret = extcon_register_notifier(edev, EXTCON_CHG_USB_DCP,
1192*4882a593Smuzhiyun 					       &charge->cable_cg_nb);
1193*4882a593Smuzhiyun 		if (ret < 0) {
1194*4882a593Smuzhiyun 			dev_err(dev, "failed to register notifier for DCP\n");
1195*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
1196*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1197*4882a593Smuzhiyun 			return ret;
1198*4882a593Smuzhiyun 		}
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 		ret = extcon_register_notifier(edev, EXTCON_CHG_USB_CDP,
1201*4882a593Smuzhiyun 					       &charge->cable_cg_nb);
1202*4882a593Smuzhiyun 		if (ret < 0) {
1203*4882a593Smuzhiyun 			dev_err(dev, "failed to register notifier for CDP\n");
1204*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
1205*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1206*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_DCP,
1207*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1208*4882a593Smuzhiyun 			return ret;
1209*4882a593Smuzhiyun 		}
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 		/* Register host */
1212*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&charge->host_work,
1213*4882a593Smuzhiyun 				  rk817_charge_host_evt_worker);
1214*4882a593Smuzhiyun 		charge->cable_host_nb.notifier_call =
1215*4882a593Smuzhiyun 			rk817_charge_host_evt_notifier;
1216*4882a593Smuzhiyun 		ret = extcon_register_notifier(edev, EXTCON_USB_VBUS_EN,
1217*4882a593Smuzhiyun 					       &charge->cable_host_nb);
1218*4882a593Smuzhiyun 		if (ret < 0) {
1219*4882a593Smuzhiyun 			dev_err(dev, "failed to register notifier for HOST\n");
1220*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
1221*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1222*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_DCP,
1223*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1224*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_CDP,
1225*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 			return ret;
1228*4882a593Smuzhiyun 		}
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 		/* Register discnt usb */
1231*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&charge->discnt_work,
1232*4882a593Smuzhiyun 				  rk817_charge_discnt_evt_worker);
1233*4882a593Smuzhiyun 		charge->cable_discnt_nb.notifier_call =
1234*4882a593Smuzhiyun 			rk817_charge_discnt_evt_notfier;
1235*4882a593Smuzhiyun 		ret = extcon_register_notifier(edev, EXTCON_USB,
1236*4882a593Smuzhiyun 					       &charge->cable_discnt_nb);
1237*4882a593Smuzhiyun 		if (ret < 0) {
1238*4882a593Smuzhiyun 			dev_err(dev, "failed to register notifier for HOST\n");
1239*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_SDP,
1240*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1241*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_DCP,
1242*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1243*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_CHG_USB_CDP,
1244*4882a593Smuzhiyun 						   &charge->cable_cg_nb);
1245*4882a593Smuzhiyun 			extcon_unregister_notifier(edev, EXTCON_USB_VBUS_EN,
1246*4882a593Smuzhiyun 						   &charge->cable_host_nb);
1247*4882a593Smuzhiyun 			return ret;
1248*4882a593Smuzhiyun 		}
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 		charge->cable_edev = edev;
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 		DBG("register typec extcon evt notifier\n");
1253*4882a593Smuzhiyun 	} else {
1254*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&charge->usb_work,
1255*4882a593Smuzhiyun 				  rk817_charge_bc_evt_worker);
1256*4882a593Smuzhiyun 		charge->bc_nb.notifier_call = rk817_charge_bc_evt_notifier;
1257*4882a593Smuzhiyun 		ret = rk_bc_detect_notifier_register(&charge->bc_nb, &bc_type);
1258*4882a593Smuzhiyun 		if (ret) {
1259*4882a593Smuzhiyun 			dev_err(dev, "failed to register notifier for bc\n");
1260*4882a593Smuzhiyun 			return -EINVAL;
1261*4882a593Smuzhiyun 	}
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 		switch (bc_type) {
1264*4882a593Smuzhiyun 		case USB_BC_TYPE_DISCNT:
1265*4882a593Smuzhiyun 			charger = USB_TYPE_NONE_CHARGER;
1266*4882a593Smuzhiyun 			break;
1267*4882a593Smuzhiyun 		case USB_BC_TYPE_SDP:
1268*4882a593Smuzhiyun 		case USB_BC_TYPE_CDP:
1269*4882a593Smuzhiyun 			charger = USB_TYPE_USB_CHARGER;
1270*4882a593Smuzhiyun 			break;
1271*4882a593Smuzhiyun 		case USB_BC_TYPE_DCP:
1272*4882a593Smuzhiyun 			charger = USB_TYPE_AC_CHARGER;
1273*4882a593Smuzhiyun 			break;
1274*4882a593Smuzhiyun 		default:
1275*4882a593Smuzhiyun 			charger = USB_TYPE_NONE_CHARGER;
1276*4882a593Smuzhiyun 			break;
1277*4882a593Smuzhiyun 		}
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 		charge->usb_charger = charger;
1280*4882a593Smuzhiyun 		if (charge->dc_charger != DC_TYPE_NONE_CHARGER)
1281*4882a593Smuzhiyun 			rk817_charge_set_chrg_param(charge,
1282*4882a593Smuzhiyun 						    charge->usb_charger);
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 		DBG("register bc evt notifier\n");
1285*4882a593Smuzhiyun 	}
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	return 0;
1288*4882a593Smuzhiyun }
1289*4882a593Smuzhiyun 
rk817_charge_pre_init(struct rk817_charger * charge)1290*4882a593Smuzhiyun static void rk817_charge_pre_init(struct rk817_charger *charge)
1291*4882a593Smuzhiyun {
1292*4882a593Smuzhiyun 	charge->max_chrg_current = charge->pdata->max_chrg_current;
1293*4882a593Smuzhiyun 	charge->max_input_current = charge->pdata->max_input_current;
1294*4882a593Smuzhiyun 	charge->max_chrg_voltage = charge->pdata->max_chrg_voltage;
1295*4882a593Smuzhiyun 	charge->min_input_voltage = charge->pdata->min_input_voltage;
1296*4882a593Smuzhiyun 	charge->chrg_finish_cur = charge->pdata->chrg_finish_cur;
1297*4882a593Smuzhiyun 	charge->chrg_term_mode = charge->pdata->chrg_term_mode;
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	rk817_charge_set_input_voltage(charge, charge->min_input_voltage);
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	rk817_charge_set_chrg_voltage(charge, charge->max_chrg_voltage);
1302*4882a593Smuzhiyun 	rk817_charge_set_chrg_current(charge, charge->max_chrg_current);
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	rk817_charge_set_chrg_finish_condition(charge);
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	if (rk817_charge_get_otg_state(charge))
1307*4882a593Smuzhiyun 		rk817_charge_otg_disable(charge);
1308*4882a593Smuzhiyun 	rk817_charge_field_write(charge, OTG_EN, OTG_DISABLE);
1309*4882a593Smuzhiyun 	rk817_charge_set_otg_in(charge, OFFLINE);
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun 	if (!charge->pdata->gate_function_disable)
1312*4882a593Smuzhiyun 		rk817_charge_sys_can_sd_disable(charge);
1313*4882a593Smuzhiyun 	rk817_charge_usb_to_sys_enable(charge);
1314*4882a593Smuzhiyun 	rk817_charge_enable_charge(charge);
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	rk817_charge_set_charge_clock(charge, CHRG_CLK_2M);
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun 
rk817_chage_debug(struct rk817_charger * charge)1319*4882a593Smuzhiyun static void rk817_chage_debug(struct rk817_charger *charge)
1320*4882a593Smuzhiyun {
1321*4882a593Smuzhiyun 	rk817_charge_get_charge_status(charge);
1322*4882a593Smuzhiyun 	DBG("OTG state : %d\n", rk817_charge_get_otg_state(charge));
1323*4882a593Smuzhiyun 	DBG("charge state: %d\n", rk817_charge_get_charge_state(charge));
1324*4882a593Smuzhiyun 	DBG("max_chrg_current: %d\n"
1325*4882a593Smuzhiyun 	    "max_input_current: %d\n"
1326*4882a593Smuzhiyun 	    "min_input_voltage: %d\n"
1327*4882a593Smuzhiyun 	    "max_chrg_voltage: %d\n"
1328*4882a593Smuzhiyun 	    "max_chrg_finish_cur: %d\n"
1329*4882a593Smuzhiyun 	    "chrg_term_mode: %d\n",
1330*4882a593Smuzhiyun 	    charge->max_chrg_current,
1331*4882a593Smuzhiyun 	    charge->max_input_current,
1332*4882a593Smuzhiyun 	    charge->min_input_voltage,
1333*4882a593Smuzhiyun 	    charge->max_chrg_voltage,
1334*4882a593Smuzhiyun 	    charge->chrg_finish_cur,
1335*4882a593Smuzhiyun 	    charge->chrg_term_mode);
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun 
rk817_charge_get_otg5v_regulator(struct rk817_charger * charge)1338*4882a593Smuzhiyun static int rk817_charge_get_otg5v_regulator(struct rk817_charger *charge)
1339*4882a593Smuzhiyun {
1340*4882a593Smuzhiyun 	int ret;
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	charge->otg5v_rdev = devm_regulator_get(charge->dev, "otg_switch");
1343*4882a593Smuzhiyun 	if (IS_ERR(charge->otg5v_rdev)) {
1344*4882a593Smuzhiyun 		ret = PTR_ERR(charge->otg5v_rdev);
1345*4882a593Smuzhiyun 		dev_warn(charge->dev, "failed to get otg regulator: %d\n", ret);
1346*4882a593Smuzhiyun 	}
1347*4882a593Smuzhiyun 
1348*4882a593Smuzhiyun 	return 0;
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun #ifdef CONFIG_OF
rk817_charge_parse_dt(struct rk817_charger * charge)1352*4882a593Smuzhiyun static int rk817_charge_parse_dt(struct rk817_charger *charge)
1353*4882a593Smuzhiyun {
1354*4882a593Smuzhiyun 	struct charger_platform_data *pdata;
1355*4882a593Smuzhiyun 	enum of_gpio_flags flags;
1356*4882a593Smuzhiyun 	struct device *dev = charge->dev;
1357*4882a593Smuzhiyun 	struct device_node *np = charge->dev->of_node;
1358*4882a593Smuzhiyun 	int ret;
1359*4882a593Smuzhiyun 
1360*4882a593Smuzhiyun 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1361*4882a593Smuzhiyun 	if (!pdata)
1362*4882a593Smuzhiyun 		return -ENOMEM;
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 	charge->pdata = pdata;
1365*4882a593Smuzhiyun 	pdata->max_chrg_current = DEFAULT_CHRG_CURRENT;
1366*4882a593Smuzhiyun 	pdata->max_input_current = DEFAULT_INPUT_CURRENT;
1367*4882a593Smuzhiyun 	pdata->max_chrg_voltage = DEFAULT_CHRG_VOLTAGE;
1368*4882a593Smuzhiyun 	pdata->min_input_voltage = DEFAULT_INPUT_VOLTAGE;
1369*4882a593Smuzhiyun 	pdata->chrg_finish_cur = DEFAULT_CHRG_TERM_CUR;
1370*4882a593Smuzhiyun 	pdata->chrg_term_mode = DEFAULT_CHRG_TERM_MODE;
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun 	pdata->extcon = of_property_read_bool(np, "extcon");
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "max_chrg_current",
1375*4882a593Smuzhiyun 				   &pdata->max_chrg_current);
1376*4882a593Smuzhiyun 	if (ret < 0)
1377*4882a593Smuzhiyun 		dev_err(dev, "max_chrg_current missing!\n");
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "max_input_current",
1380*4882a593Smuzhiyun 				   &pdata->max_input_current);
1381*4882a593Smuzhiyun 	if (ret < 0)
1382*4882a593Smuzhiyun 		dev_err(dev, "max_input_current missing!\n");
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "max_chrg_voltage",
1385*4882a593Smuzhiyun 				   &pdata->max_chrg_voltage);
1386*4882a593Smuzhiyun 	if (ret < 0)
1387*4882a593Smuzhiyun 		dev_err(dev, "max_chrg_voltage missing!\n");
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "min_input_voltage",
1390*4882a593Smuzhiyun 				   &pdata->min_input_voltage);
1391*4882a593Smuzhiyun 	if (ret < 0)
1392*4882a593Smuzhiyun 		dev_WARN(dev, "min_input_voltage missing!\n");
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "chrg_finish_cur",
1395*4882a593Smuzhiyun 				   &pdata->chrg_finish_cur);
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun 	if (ret < 0)
1398*4882a593Smuzhiyun 		dev_WARN(dev, "chrg_term_mode missing!\n");
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "chrg_term_mode",
1401*4882a593Smuzhiyun 				   &pdata->chrg_term_mode);
1402*4882a593Smuzhiyun 	if (ret < 0)
1403*4882a593Smuzhiyun 		dev_WARN(dev, "chrg_term_mode missing!\n");
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "virtual_power", &pdata->virtual_power);
1406*4882a593Smuzhiyun 	if (ret < 0)
1407*4882a593Smuzhiyun 		dev_err(dev, "virtual_power missing!\n");
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "power_dc2otg", &pdata->power_dc2otg);
1410*4882a593Smuzhiyun 	if (ret < 0)
1411*4882a593Smuzhiyun 		dev_err(dev, "power_dc2otg missing!\n");
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "sample_res", &pdata->sample_res);
1414*4882a593Smuzhiyun 	if (ret < 0) {
1415*4882a593Smuzhiyun 		pdata->sample_res = SAMPLE_RES_10MR;
1416*4882a593Smuzhiyun 		dev_err(dev, "sample_res missing!\n");
1417*4882a593Smuzhiyun 	}
1418*4882a593Smuzhiyun 
1419*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "otg5v_suspend_enable",
1420*4882a593Smuzhiyun 				   &pdata->otg5v_suspend_enable);
1421*4882a593Smuzhiyun 	if (ret < 0) {
1422*4882a593Smuzhiyun 		pdata->otg5v_suspend_enable = 1;
1423*4882a593Smuzhiyun 		dev_err(dev, "otg5v_suspend_enable missing!\n");
1424*4882a593Smuzhiyun 	}
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "gate_function_disable",
1427*4882a593Smuzhiyun 				   &pdata->gate_function_disable);
1428*4882a593Smuzhiyun 	if (ret < 0)
1429*4882a593Smuzhiyun 		dev_err(dev, "gate_function_disable missing!\n");
1430*4882a593Smuzhiyun 
1431*4882a593Smuzhiyun 	if (!is_battery_exist(charge))
1432*4882a593Smuzhiyun 		pdata->virtual_power = 1;
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun 	charge->res_div = (charge->pdata->sample_res == SAMPLE_RES_10MR) ?
1435*4882a593Smuzhiyun 		       SAMPLE_RES_DIV1 : SAMPLE_RES_DIV2;
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	if (!of_find_property(np, "dc_det_gpio", &ret)) {
1438*4882a593Smuzhiyun 		pdata->support_dc_det = false;
1439*4882a593Smuzhiyun 		DBG("not support dc\n");
1440*4882a593Smuzhiyun 	} else {
1441*4882a593Smuzhiyun 		pdata->support_dc_det = true;
1442*4882a593Smuzhiyun 		pdata->dc_det_pin = of_get_named_gpio_flags(np, "dc_det_gpio",
1443*4882a593Smuzhiyun 							    0, &flags);
1444*4882a593Smuzhiyun 		if (gpio_is_valid(pdata->dc_det_pin)) {
1445*4882a593Smuzhiyun 			DBG("support dc\n");
1446*4882a593Smuzhiyun 			pdata->dc_det_level = (flags & OF_GPIO_ACTIVE_LOW) ?
1447*4882a593Smuzhiyun 					       0 : 1;
1448*4882a593Smuzhiyun 		} else {
1449*4882a593Smuzhiyun 			dev_err(dev, "invalid dc det gpio!\n");
1450*4882a593Smuzhiyun 			return -EINVAL;
1451*4882a593Smuzhiyun 		}
1452*4882a593Smuzhiyun 	}
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	DBG("input_current:%d\n"
1455*4882a593Smuzhiyun 		"input_min_voltage: %d\n"
1456*4882a593Smuzhiyun 	    "chrg_current:%d\n"
1457*4882a593Smuzhiyun 	    "chrg_voltage:%d\n"
1458*4882a593Smuzhiyun 	    "sample_res:%d\n"
1459*4882a593Smuzhiyun 	    "extcon:%d\n"
1460*4882a593Smuzhiyun 	    "virtual_power:%d\n"
1461*4882a593Smuzhiyun 	    "power_dc2otg:%d\n",
1462*4882a593Smuzhiyun 	    pdata->max_input_current, pdata->min_input_voltage,
1463*4882a593Smuzhiyun 	    pdata->max_chrg_current,  pdata->max_chrg_voltage,
1464*4882a593Smuzhiyun 	    pdata->sample_res, pdata->extcon,
1465*4882a593Smuzhiyun 	    pdata->virtual_power, pdata->power_dc2otg);
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun 	return 0;
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun #else
rk817_charge_parse_dt(struct rk817_charger * charge)1470*4882a593Smuzhiyun static int rk817_charge_parse_dt(struct rk817_charger *charge)
1471*4882a593Smuzhiyun {
1472*4882a593Smuzhiyun 	return -ENODEV;
1473*4882a593Smuzhiyun }
1474*4882a593Smuzhiyun #endif
1475*4882a593Smuzhiyun 
rk817_charge_irq_delay_work(struct work_struct * work)1476*4882a593Smuzhiyun static void rk817_charge_irq_delay_work(struct work_struct *work)
1477*4882a593Smuzhiyun {
1478*4882a593Smuzhiyun 	struct rk817_charger *charge = container_of(work,
1479*4882a593Smuzhiyun 			struct rk817_charger, irq_work.work);
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	if (charge->plugin_trigger) {
1482*4882a593Smuzhiyun 		DBG("pmic: plug in\n");
1483*4882a593Smuzhiyun 		charge->plugin_trigger = 0;
1484*4882a593Smuzhiyun 		if (charge->pdata->extcon)
1485*4882a593Smuzhiyun 			queue_delayed_work(charge->usb_charger_wq, &charge->usb_work,
1486*4882a593Smuzhiyun 					   msecs_to_jiffies(10));
1487*4882a593Smuzhiyun 	} else if (charge->plugout_trigger) {
1488*4882a593Smuzhiyun 		DBG("pmic: plug out\n");
1489*4882a593Smuzhiyun 		charge->plugout_trigger = 0;
1490*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, USB_TYPE_NONE_CHARGER);
1491*4882a593Smuzhiyun 		rk817_charge_set_chrg_param(charge, DC_TYPE_NONE_CHARGER);
1492*4882a593Smuzhiyun 	} else {
1493*4882a593Smuzhiyun 		DBG("pmic: unknown irq\n");
1494*4882a593Smuzhiyun 	}
1495*4882a593Smuzhiyun }
1496*4882a593Smuzhiyun 
rk817_plug_in_isr(int irq,void * cg)1497*4882a593Smuzhiyun static irqreturn_t rk817_plug_in_isr(int irq, void *cg)
1498*4882a593Smuzhiyun {
1499*4882a593Smuzhiyun 	struct rk817_charger *charge;
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	charge = (struct rk817_charger *)cg;
1502*4882a593Smuzhiyun 	charge->plugin_trigger = 1;
1503*4882a593Smuzhiyun 	queue_delayed_work(charge->usb_charger_wq, &charge->irq_work,
1504*4882a593Smuzhiyun 			   msecs_to_jiffies(10));
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	return IRQ_HANDLED;
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun 
rk817_plug_out_isr(int irq,void * cg)1509*4882a593Smuzhiyun static irqreturn_t rk817_plug_out_isr(int irq, void *cg)
1510*4882a593Smuzhiyun {
1511*4882a593Smuzhiyun 	struct rk817_charger *charge;
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	charge = (struct rk817_charger *)cg;
1514*4882a593Smuzhiyun 	charge->plugout_trigger = 1;
1515*4882a593Smuzhiyun 	queue_delayed_work(charge->usb_charger_wq, &charge->irq_work,
1516*4882a593Smuzhiyun 			   msecs_to_jiffies(10));
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	return IRQ_HANDLED;
1519*4882a593Smuzhiyun }
1520*4882a593Smuzhiyun 
rk817_charge_init_irqs(struct rk817_charger * charge)1521*4882a593Smuzhiyun static int rk817_charge_init_irqs(struct rk817_charger *charge)
1522*4882a593Smuzhiyun {
1523*4882a593Smuzhiyun 	struct rk808 *rk817 = charge->rk817;
1524*4882a593Smuzhiyun 	struct platform_device *pdev = charge->pdev;
1525*4882a593Smuzhiyun 	int ret, plug_in_irq, plug_out_irq;
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 	plug_in_irq = regmap_irq_get_virq(rk817->irq_data, RK817_IRQ_PLUG_IN);
1528*4882a593Smuzhiyun 	if (plug_in_irq < 0) {
1529*4882a593Smuzhiyun 		dev_err(charge->dev, "plug_in_irq request failed!\n");
1530*4882a593Smuzhiyun 		return plug_in_irq;
1531*4882a593Smuzhiyun 	}
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 	plug_out_irq = regmap_irq_get_virq(rk817->irq_data, RK817_IRQ_PLUG_OUT);
1534*4882a593Smuzhiyun 	if (plug_out_irq < 0) {
1535*4882a593Smuzhiyun 		dev_err(charge->dev, "plug_out_irq request failed!\n");
1536*4882a593Smuzhiyun 		return plug_out_irq;
1537*4882a593Smuzhiyun 	}
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(charge->dev, plug_in_irq, NULL,
1540*4882a593Smuzhiyun 					rk817_plug_in_isr,
1541*4882a593Smuzhiyun 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1542*4882a593Smuzhiyun 					"rk817_plug_in", charge);
1543*4882a593Smuzhiyun 	if (ret) {
1544*4882a593Smuzhiyun 		dev_err(&pdev->dev, "plug_in_irq request failed!\n");
1545*4882a593Smuzhiyun 		return ret;
1546*4882a593Smuzhiyun 	}
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(charge->dev, plug_out_irq, NULL,
1549*4882a593Smuzhiyun 					rk817_plug_out_isr,
1550*4882a593Smuzhiyun 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1551*4882a593Smuzhiyun 					"rk817_plug_out", charge);
1552*4882a593Smuzhiyun 	if (ret) {
1553*4882a593Smuzhiyun 		dev_err(&pdev->dev, "plug_out_irq request failed!\n");
1554*4882a593Smuzhiyun 		return ret;
1555*4882a593Smuzhiyun 	}
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 	charge->plugin_irq = plug_in_irq;
1558*4882a593Smuzhiyun 	charge->plugout_irq = plug_out_irq;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&charge->irq_work, rk817_charge_irq_delay_work);
1561*4882a593Smuzhiyun 
1562*4882a593Smuzhiyun 	return 0;
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun static const struct of_device_id rk817_charge_of_match[] = {
1566*4882a593Smuzhiyun 	{ .compatible = "rk817,charger", },
1567*4882a593Smuzhiyun 	{ },
1568*4882a593Smuzhiyun };
1569*4882a593Smuzhiyun 
rk817_charge_probe(struct platform_device * pdev)1570*4882a593Smuzhiyun static int rk817_charge_probe(struct platform_device *pdev)
1571*4882a593Smuzhiyun {
1572*4882a593Smuzhiyun 	struct rk808 *rk817 = dev_get_drvdata(pdev->dev.parent);
1573*4882a593Smuzhiyun 	const struct of_device_id *of_id =
1574*4882a593Smuzhiyun 			of_match_device(rk817_charge_of_match, &pdev->dev);
1575*4882a593Smuzhiyun 	struct i2c_client *client = rk817->i2c;
1576*4882a593Smuzhiyun 	struct rk817_charger *charge;
1577*4882a593Smuzhiyun 	int i;
1578*4882a593Smuzhiyun 	int ret;
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun 	if (!of_id) {
1581*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Failed to find matching dt id\n");
1582*4882a593Smuzhiyun 		return -ENODEV;
1583*4882a593Smuzhiyun 	}
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun 	charge = devm_kzalloc(&pdev->dev, sizeof(*charge), GFP_KERNEL);
1586*4882a593Smuzhiyun 	if (!charge)
1587*4882a593Smuzhiyun 		return -EINVAL;
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 	charge->rk817 = rk817;
1590*4882a593Smuzhiyun 	charge->pdev = pdev;
1591*4882a593Smuzhiyun 	charge->dev = &pdev->dev;
1592*4882a593Smuzhiyun 	charge->client = client;
1593*4882a593Smuzhiyun 	platform_set_drvdata(pdev, charge);
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun 	charge->regmap = rk817->regmap;
1596*4882a593Smuzhiyun 	if (IS_ERR(charge->regmap)) {
1597*4882a593Smuzhiyun 		dev_err(charge->dev, "Failed to initialize regmap\n");
1598*4882a593Smuzhiyun 		return -EINVAL;
1599*4882a593Smuzhiyun 	}
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(rk817_charge_reg_fields); i++) {
1602*4882a593Smuzhiyun 		const struct reg_field *reg_fields = rk817_charge_reg_fields;
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 		charge->rmap_fields[i] =
1605*4882a593Smuzhiyun 			devm_regmap_field_alloc(charge->dev,
1606*4882a593Smuzhiyun 						charge->regmap,
1607*4882a593Smuzhiyun 						reg_fields[i]);
1608*4882a593Smuzhiyun 		if (IS_ERR(charge->rmap_fields[i])) {
1609*4882a593Smuzhiyun 			dev_err(charge->dev, "cannot allocate regmap field\n");
1610*4882a593Smuzhiyun 			return PTR_ERR(charge->rmap_fields[i]);
1611*4882a593Smuzhiyun 		}
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 	ret = rk817_charge_parse_dt(charge);
1615*4882a593Smuzhiyun 	if (ret < 0) {
1616*4882a593Smuzhiyun 		dev_err(charge->dev, "charge parse dt failed!\n");
1617*4882a593Smuzhiyun 		return ret;
1618*4882a593Smuzhiyun 	}
1619*4882a593Smuzhiyun 	rk817_charge_get_otg5v_regulator(charge);
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 	rk817_charge_pre_init(charge);
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	ret = rk817_charge_init_power_supply(charge);
1624*4882a593Smuzhiyun 	if (ret) {
1625*4882a593Smuzhiyun 		dev_err(charge->dev, "init power supply fail!\n");
1626*4882a593Smuzhiyun 		return ret;
1627*4882a593Smuzhiyun 	}
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	ret = rk817_charge_init_dc(charge);
1630*4882a593Smuzhiyun 	if (ret) {
1631*4882a593Smuzhiyun 		dev_err(charge->dev, "init dc failed!\n");
1632*4882a593Smuzhiyun 		return ret;
1633*4882a593Smuzhiyun 	}
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	ret = rk817_charge_usb_init(charge);
1636*4882a593Smuzhiyun 	if (ret) {
1637*4882a593Smuzhiyun 		dev_err(charge->dev, "init usb failed!\n");
1638*4882a593Smuzhiyun 		return ret;
1639*4882a593Smuzhiyun 	}
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 	ret = rk817_charge_init_irqs(charge);
1642*4882a593Smuzhiyun 	if (ret) {
1643*4882a593Smuzhiyun 		dev_err(charge->dev, "init irqs failed!\n");
1644*4882a593Smuzhiyun 		goto irq_fail;
1645*4882a593Smuzhiyun 	}
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 	if (charge->pdata->extcon) {
1648*4882a593Smuzhiyun 		schedule_delayed_work(&charge->host_work, 0);
1649*4882a593Smuzhiyun 		schedule_delayed_work(&charge->usb_work, 0);
1650*4882a593Smuzhiyun 	}
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 	rk817_chage_debug(charge);
1653*4882a593Smuzhiyun 	DBG("driver version: %s\n", CHARGE_DRIVER_VERSION);
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 	return 0;
1656*4882a593Smuzhiyun irq_fail:
1657*4882a593Smuzhiyun 	if (charge->pdata->extcon) {
1658*4882a593Smuzhiyun 		cancel_delayed_work_sync(&charge->host_work);
1659*4882a593Smuzhiyun 		cancel_delayed_work_sync(&charge->discnt_work);
1660*4882a593Smuzhiyun 	}
1661*4882a593Smuzhiyun 
1662*4882a593Smuzhiyun 	cancel_delayed_work_sync(&charge->usb_work);
1663*4882a593Smuzhiyun 	cancel_delayed_work_sync(&charge->dc_work);
1664*4882a593Smuzhiyun 	cancel_delayed_work_sync(&charge->irq_work);
1665*4882a593Smuzhiyun 	destroy_workqueue(charge->usb_charger_wq);
1666*4882a593Smuzhiyun 	destroy_workqueue(charge->dc_charger_wq);
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 	if (charge->pdata->extcon) {
1669*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1670*4882a593Smuzhiyun 					   EXTCON_CHG_USB_SDP,
1671*4882a593Smuzhiyun 					   &charge->cable_cg_nb);
1672*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1673*4882a593Smuzhiyun 					   EXTCON_CHG_USB_DCP,
1674*4882a593Smuzhiyun 					   &charge->cable_cg_nb);
1675*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1676*4882a593Smuzhiyun 					   EXTCON_CHG_USB_CDP,
1677*4882a593Smuzhiyun 					   &charge->cable_cg_nb);
1678*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1679*4882a593Smuzhiyun 					   EXTCON_USB_VBUS_EN,
1680*4882a593Smuzhiyun 					   &charge->cable_host_nb);
1681*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1682*4882a593Smuzhiyun 					   EXTCON_USB,
1683*4882a593Smuzhiyun 					   &charge->cable_discnt_nb);
1684*4882a593Smuzhiyun 	} else {
1685*4882a593Smuzhiyun 		rk_bc_detect_notifier_unregister(&charge->bc_nb);
1686*4882a593Smuzhiyun 	}
1687*4882a593Smuzhiyun 
1688*4882a593Smuzhiyun 	return ret;
1689*4882a593Smuzhiyun }
1690*4882a593Smuzhiyun 
1691*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
rk817_charge_pm_suspend(struct device * dev)1692*4882a593Smuzhiyun static int  rk817_charge_pm_suspend(struct device *dev)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
1695*4882a593Smuzhiyun 	struct rk817_charger *charge = dev_get_drvdata(&pdev->dev);
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	charge->otg_slp_state = rk817_charge_get_otg_slp_state(charge);
1698*4882a593Smuzhiyun 
1699*4882a593Smuzhiyun 	/* enable sleep boost5v and otg5v */
1700*4882a593Smuzhiyun 	if (charge->pdata->otg5v_suspend_enable) {
1701*4882a593Smuzhiyun 		if ((charge->otg_in && !charge->dc_in) ||
1702*4882a593Smuzhiyun 		    (charge->otg_in && charge->dc_in &&
1703*4882a593Smuzhiyun 		    !charge->pdata->power_dc2otg)) {
1704*4882a593Smuzhiyun 			rk817_charge_otg_slp_enable(charge);
1705*4882a593Smuzhiyun 			DBG("suspend: otg 5v on\n");
1706*4882a593Smuzhiyun 			return 0;
1707*4882a593Smuzhiyun 		}
1708*4882a593Smuzhiyun 	}
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 	/* disable sleep otg5v */
1711*4882a593Smuzhiyun 	rk817_charge_otg_slp_disable(charge);
1712*4882a593Smuzhiyun 	DBG("suspend: otg 5v off\n");
1713*4882a593Smuzhiyun 	return 0;
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun 
rk817_charge_pm_resume(struct device * dev)1716*4882a593Smuzhiyun static int rk817_charge_pm_resume(struct device *dev)
1717*4882a593Smuzhiyun {
1718*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
1719*4882a593Smuzhiyun 	struct rk817_charger *charge = dev_get_drvdata(&pdev->dev);
1720*4882a593Smuzhiyun 
1721*4882a593Smuzhiyun 	/* resume sleep boost5v and otg5v */
1722*4882a593Smuzhiyun 	if (charge->otg_slp_state)
1723*4882a593Smuzhiyun 		rk817_charge_otg_slp_enable(charge);
1724*4882a593Smuzhiyun 
1725*4882a593Smuzhiyun 	return 0;
1726*4882a593Smuzhiyun }
1727*4882a593Smuzhiyun #endif
1728*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(rk817_charge_pm_ops,
1729*4882a593Smuzhiyun 	rk817_charge_pm_suspend, rk817_charge_pm_resume);
1730*4882a593Smuzhiyun 
rk817_charger_shutdown(struct platform_device * dev)1731*4882a593Smuzhiyun static void rk817_charger_shutdown(struct platform_device *dev)
1732*4882a593Smuzhiyun {
1733*4882a593Smuzhiyun 	struct rk817_charger *charge =  platform_get_drvdata(dev);
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun 	/* type-c only */
1736*4882a593Smuzhiyun 	if (charge->pdata->extcon) {
1737*4882a593Smuzhiyun 		cancel_delayed_work_sync(&charge->host_work);
1738*4882a593Smuzhiyun 		cancel_delayed_work_sync(&charge->discnt_work);
1739*4882a593Smuzhiyun 	}
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 	rk817_charge_set_otg_state(charge, USB_OTG_POWER_OFF);
1742*4882a593Smuzhiyun 	rk817_charge_boost_disable(charge);
1743*4882a593Smuzhiyun 	disable_irq(charge->plugin_irq);
1744*4882a593Smuzhiyun 	disable_irq(charge->plugout_irq);
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun 	cancel_delayed_work_sync(&charge->usb_work);
1747*4882a593Smuzhiyun 	cancel_delayed_work_sync(&charge->dc_work);
1748*4882a593Smuzhiyun 	cancel_delayed_work_sync(&charge->irq_work);
1749*4882a593Smuzhiyun 	flush_workqueue(charge->usb_charger_wq);
1750*4882a593Smuzhiyun 	flush_workqueue(charge->dc_charger_wq);
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun 	if (charge->pdata->extcon) {
1753*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1754*4882a593Smuzhiyun 					   EXTCON_CHG_USB_SDP,
1755*4882a593Smuzhiyun 					   &charge->cable_cg_nb);
1756*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1757*4882a593Smuzhiyun 					   EXTCON_CHG_USB_DCP,
1758*4882a593Smuzhiyun 					   &charge->cable_cg_nb);
1759*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1760*4882a593Smuzhiyun 					   EXTCON_CHG_USB_CDP,
1761*4882a593Smuzhiyun 					   &charge->cable_cg_nb);
1762*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev,
1763*4882a593Smuzhiyun 					   EXTCON_USB_VBUS_EN,
1764*4882a593Smuzhiyun 					   &charge->cable_host_nb);
1765*4882a593Smuzhiyun 		extcon_unregister_notifier(charge->cable_edev, EXTCON_USB,
1766*4882a593Smuzhiyun 					   &charge->cable_discnt_nb);
1767*4882a593Smuzhiyun 	} else {
1768*4882a593Smuzhiyun 		rk_bc_detect_notifier_unregister(&charge->bc_nb);
1769*4882a593Smuzhiyun 	}
1770*4882a593Smuzhiyun 
1771*4882a593Smuzhiyun 	DBG("shutdown: ac=%d usb=%d dc=%d otg=%d\n",
1772*4882a593Smuzhiyun 	    charge->ac_in, charge->usb_in, charge->dc_in, charge->otg_in);
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun static struct platform_driver rk817_charge_driver = {
1776*4882a593Smuzhiyun 	.probe = rk817_charge_probe,
1777*4882a593Smuzhiyun 	.shutdown = rk817_charger_shutdown,
1778*4882a593Smuzhiyun 	.driver = {
1779*4882a593Smuzhiyun 		.name = "rk817-charger",
1780*4882a593Smuzhiyun 		.pm = &rk817_charge_pm_ops,
1781*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(rk817_charge_of_match),
1782*4882a593Smuzhiyun 	},
1783*4882a593Smuzhiyun };
1784*4882a593Smuzhiyun 
rk817_charge_init(void)1785*4882a593Smuzhiyun static int __init rk817_charge_init(void)
1786*4882a593Smuzhiyun {
1787*4882a593Smuzhiyun 	return platform_driver_register(&rk817_charge_driver);
1788*4882a593Smuzhiyun }
1789*4882a593Smuzhiyun fs_initcall_sync(rk817_charge_init);
1790*4882a593Smuzhiyun 
rk817_charge_exit(void)1791*4882a593Smuzhiyun static void __exit rk817_charge_exit(void)
1792*4882a593Smuzhiyun {
1793*4882a593Smuzhiyun 	platform_driver_unregister(&rk817_charge_driver);
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun module_exit(rk817_charge_exit);
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun MODULE_DESCRIPTION("RK817 Charge driver");
1798*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1799