• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * axp288_charger.c - X-power AXP288 PMIC Charger driver
3  *
4  * Copyright (C) 2014 Intel Corporation
5  * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 #include <linux/module.h>
18 #include <linux/device.h>
19 #include <linux/regmap.h>
20 #include <linux/workqueue.h>
21 #include <linux/delay.h>
22 #include <linux/platform_device.h>
23 #include <linux/usb/otg.h>
24 #include <linux/notifier.h>
25 #include <linux/power_supply.h>
26 #include <linux/notifier.h>
27 #include <linux/property.h>
28 #include <linux/mfd/axp20x.h>
29 #include <linux/extcon.h>
30 
31 #define PS_STAT_VBUS_TRIGGER		(1 << 0)
32 #define PS_STAT_BAT_CHRG_DIR		(1 << 2)
33 #define PS_STAT_VBAT_ABOVE_VHOLD	(1 << 3)
34 #define PS_STAT_VBUS_VALID		(1 << 4)
35 #define PS_STAT_VBUS_PRESENT		(1 << 5)
36 
37 #define CHRG_STAT_BAT_SAFE_MODE		(1 << 3)
38 #define CHRG_STAT_BAT_VALID		(1 << 4)
39 #define CHRG_STAT_BAT_PRESENT		(1 << 5)
40 #define CHRG_STAT_CHARGING		(1 << 6)
41 #define CHRG_STAT_PMIC_OTP		(1 << 7)
42 
43 #define VBUS_ISPOUT_CUR_LIM_MASK	0x03
44 #define VBUS_ISPOUT_CUR_LIM_BIT_POS	0
45 #define VBUS_ISPOUT_CUR_LIM_900MA	0x0	/* 900mA */
46 #define VBUS_ISPOUT_CUR_LIM_1500MA	0x1	/* 1500mA */
47 #define VBUS_ISPOUT_CUR_LIM_2000MA	0x2	/* 2000mA */
48 #define VBUS_ISPOUT_CUR_NO_LIM		0x3	/* 2500mA */
49 #define VBUS_ISPOUT_VHOLD_SET_MASK	0x31
50 #define VBUS_ISPOUT_VHOLD_SET_BIT_POS	0x3
51 #define VBUS_ISPOUT_VHOLD_SET_OFFSET	4000	/* 4000mV */
52 #define VBUS_ISPOUT_VHOLD_SET_LSB_RES	100	/* 100mV */
53 #define VBUS_ISPOUT_VHOLD_SET_4300MV	0x3	/* 4300mV */
54 #define VBUS_ISPOUT_VBUS_PATH_DIS	(1 << 7)
55 
56 #define CHRG_CCCV_CC_MASK		0xf		/* 4 bits */
57 #define CHRG_CCCV_CC_BIT_POS		0
58 #define CHRG_CCCV_CC_OFFSET		200		/* 200mA */
59 #define CHRG_CCCV_CC_LSB_RES		200		/* 200mA */
60 #define CHRG_CCCV_ITERM_20P		(1 << 4)	/* 20% of CC */
61 #define CHRG_CCCV_CV_MASK		0x60		/* 2 bits */
62 #define CHRG_CCCV_CV_BIT_POS		5
63 #define CHRG_CCCV_CV_4100MV		0x0		/* 4.10V */
64 #define CHRG_CCCV_CV_4150MV		0x1		/* 4.15V */
65 #define CHRG_CCCV_CV_4200MV		0x2		/* 4.20V */
66 #define CHRG_CCCV_CV_4350MV		0x3		/* 4.35V */
67 #define CHRG_CCCV_CHG_EN		(1 << 7)
68 
69 #define CNTL2_CC_TIMEOUT_MASK		0x3	/* 2 bits */
70 #define CNTL2_CC_TIMEOUT_OFFSET		6	/* 6 Hrs */
71 #define CNTL2_CC_TIMEOUT_LSB_RES	2	/* 2 Hrs */
72 #define CNTL2_CC_TIMEOUT_12HRS		0x3	/* 12 Hrs */
73 #define CNTL2_CHGLED_TYPEB		(1 << 4)
74 #define CNTL2_CHG_OUT_TURNON		(1 << 5)
75 #define CNTL2_PC_TIMEOUT_MASK		0xC0
76 #define CNTL2_PC_TIMEOUT_OFFSET		40	/* 40 mins */
77 #define CNTL2_PC_TIMEOUT_LSB_RES	10	/* 10 mins */
78 #define CNTL2_PC_TIMEOUT_70MINS		0x3
79 
80 #define CHRG_ILIM_TEMP_LOOP_EN		(1 << 3)
81 #define CHRG_VBUS_ILIM_MASK		0xf0
82 #define CHRG_VBUS_ILIM_BIT_POS		4
83 #define CHRG_VBUS_ILIM_100MA		0x0	/* 100mA */
84 #define CHRG_VBUS_ILIM_500MA		0x1	/* 500mA */
85 #define CHRG_VBUS_ILIM_900MA		0x2	/* 900mA */
86 #define CHRG_VBUS_ILIM_1500MA		0x3	/* 1500mA */
87 #define CHRG_VBUS_ILIM_2000MA		0x4	/* 2000mA */
88 #define CHRG_VBUS_ILIM_2500MA		0x5	/* 2500mA */
89 #define CHRG_VBUS_ILIM_3000MA		0x6	/* 3000mA */
90 
91 #define CHRG_VLTFC_0C			0xA5	/* 0 DegC */
92 #define CHRG_VHTFC_45C			0x1F	/* 45 DegC */
93 
94 #define BAT_IRQ_CFG_CHRG_DONE		(1 << 2)
95 #define BAT_IRQ_CFG_CHRG_START		(1 << 3)
96 #define BAT_IRQ_CFG_BAT_SAFE_EXIT	(1 << 4)
97 #define BAT_IRQ_CFG_BAT_SAFE_ENTER	(1 << 5)
98 #define BAT_IRQ_CFG_BAT_DISCON		(1 << 6)
99 #define BAT_IRQ_CFG_BAT_CONN		(1 << 7)
100 #define BAT_IRQ_CFG_BAT_MASK		0xFC
101 
102 #define TEMP_IRQ_CFG_QCBTU		(1 << 4)
103 #define TEMP_IRQ_CFG_CBTU		(1 << 5)
104 #define TEMP_IRQ_CFG_QCBTO		(1 << 6)
105 #define TEMP_IRQ_CFG_CBTO		(1 << 7)
106 #define TEMP_IRQ_CFG_MASK		0xF0
107 
108 #define FG_CNTL_OCV_ADJ_EN		(1 << 3)
109 
110 #define CV_4100MV			4100	/* 4100mV */
111 #define CV_4150MV			4150	/* 4150mV */
112 #define CV_4200MV			4200	/* 4200mV */
113 #define CV_4350MV			4350	/* 4350mV */
114 
115 #define CC_200MA			200	/*  200mA */
116 #define CC_600MA			600	/*  600mA */
117 #define CC_800MA			800	/*  800mA */
118 #define CC_1000MA			1000	/* 1000mA */
119 #define CC_1600MA			1600	/* 1600mA */
120 #define CC_2000MA			2000	/* 2000mA */
121 
122 #define ILIM_100MA			100	/* 100mA */
123 #define ILIM_500MA			500	/* 500mA */
124 #define ILIM_900MA			900	/* 900mA */
125 #define ILIM_1500MA			1500	/* 1500mA */
126 #define ILIM_2000MA			2000	/* 2000mA */
127 #define ILIM_2500MA			2500	/* 2500mA */
128 #define ILIM_3000MA			3000	/* 3000mA */
129 
130 #define AXP288_EXTCON_DEV_NAME		"axp288_extcon"
131 
132 #define AXP288_EXTCON_SLOW_CHARGER		"SLOW-CHARGER"
133 #define AXP288_EXTCON_DOWNSTREAM_CHARGER	"CHARGE-DOWNSTREAM"
134 #define AXP288_EXTCON_FAST_CHARGER		"FAST-CHARGER"
135 
136 enum {
137 	VBUS_OV_IRQ = 0,
138 	CHARGE_DONE_IRQ,
139 	CHARGE_CHARGING_IRQ,
140 	BAT_SAFE_QUIT_IRQ,
141 	BAT_SAFE_ENTER_IRQ,
142 	QCBTU_IRQ,
143 	CBTU_IRQ,
144 	QCBTO_IRQ,
145 	CBTO_IRQ,
146 	CHRG_INTR_END,
147 };
148 
149 struct axp288_chrg_info {
150 	struct platform_device *pdev;
151 	struct axp20x_chrg_pdata *pdata;
152 	struct regmap *regmap;
153 	struct regmap_irq_chip_data *regmap_irqc;
154 	int irq[CHRG_INTR_END];
155 	struct power_supply *psy_usb;
156 	struct mutex lock;
157 
158 	/* OTG/Host mode */
159 	struct {
160 		struct work_struct work;
161 		struct extcon_specific_cable_nb cable;
162 		struct notifier_block id_nb;
163 		bool id_short;
164 	} otg;
165 
166 	/* SDP/CDP/DCP USB charging cable notifications */
167 	struct {
168 		struct extcon_dev *edev;
169 		bool connected;
170 		enum power_supply_type chg_type;
171 		struct notifier_block nb;
172 		struct work_struct work;
173 	} cable;
174 
175 	int health;
176 	int inlmt;
177 	int cc;
178 	int cv;
179 	int max_cc;
180 	int max_cv;
181 	bool online;
182 	bool present;
183 	bool enable_charger;
184 	bool is_charger_enabled;
185 };
186 
axp288_charger_set_cc(struct axp288_chrg_info * info,int cc)187 static inline int axp288_charger_set_cc(struct axp288_chrg_info *info, int cc)
188 {
189 	u8 reg_val;
190 	int ret;
191 
192 	if (cc < CHRG_CCCV_CC_OFFSET)
193 		cc = CHRG_CCCV_CC_OFFSET;
194 	else if (cc > info->max_cc)
195 		cc = info->max_cc;
196 
197 	reg_val = (cc - CHRG_CCCV_CC_OFFSET) / CHRG_CCCV_CC_LSB_RES;
198 	cc = (reg_val * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET;
199 	reg_val = reg_val << CHRG_CCCV_CC_BIT_POS;
200 
201 	ret = regmap_update_bits(info->regmap,
202 				AXP20X_CHRG_CTRL1,
203 				CHRG_CCCV_CC_MASK, reg_val);
204 	if (ret >= 0)
205 		info->cc = cc;
206 
207 	return ret;
208 }
209 
axp288_charger_set_cv(struct axp288_chrg_info * info,int cv)210 static inline int axp288_charger_set_cv(struct axp288_chrg_info *info, int cv)
211 {
212 	u8 reg_val;
213 	int ret;
214 
215 	if (cv <= CV_4100MV) {
216 		reg_val = CHRG_CCCV_CV_4100MV;
217 		cv = CV_4100MV;
218 	} else if (cv <= CV_4150MV) {
219 		reg_val = CHRG_CCCV_CV_4150MV;
220 		cv = CV_4150MV;
221 	} else if (cv <= CV_4200MV) {
222 		reg_val = CHRG_CCCV_CV_4200MV;
223 		cv = CV_4200MV;
224 	} else {
225 		reg_val = CHRG_CCCV_CV_4350MV;
226 		cv = CV_4350MV;
227 	}
228 
229 	reg_val = reg_val << CHRG_CCCV_CV_BIT_POS;
230 
231 	ret = regmap_update_bits(info->regmap,
232 				AXP20X_CHRG_CTRL1,
233 				CHRG_CCCV_CV_MASK, reg_val);
234 
235 	if (ret >= 0)
236 		info->cv = cv;
237 
238 	return ret;
239 }
240 
axp288_charger_set_vbus_inlmt(struct axp288_chrg_info * info,int inlmt)241 static inline int axp288_charger_set_vbus_inlmt(struct axp288_chrg_info *info,
242 					   int inlmt)
243 {
244 	int ret;
245 	unsigned int val;
246 	u8 reg_val;
247 
248 	/* Read in limit register */
249 	ret = regmap_read(info->regmap, AXP20X_CHRG_BAK_CTRL, &val);
250 	if (ret < 0)
251 		goto set_inlmt_fail;
252 
253 	if (inlmt <= ILIM_100MA) {
254 		reg_val = CHRG_VBUS_ILIM_100MA;
255 		inlmt = ILIM_100MA;
256 	} else if (inlmt <= ILIM_500MA) {
257 		reg_val = CHRG_VBUS_ILIM_500MA;
258 		inlmt = ILIM_500MA;
259 	} else if (inlmt <= ILIM_900MA) {
260 		reg_val = CHRG_VBUS_ILIM_900MA;
261 		inlmt = ILIM_900MA;
262 	} else if (inlmt <= ILIM_1500MA) {
263 		reg_val = CHRG_VBUS_ILIM_1500MA;
264 		inlmt = ILIM_1500MA;
265 	} else if (inlmt <= ILIM_2000MA) {
266 		reg_val = CHRG_VBUS_ILIM_2000MA;
267 		inlmt = ILIM_2000MA;
268 	} else if (inlmt <= ILIM_2500MA) {
269 		reg_val = CHRG_VBUS_ILIM_2500MA;
270 		inlmt = ILIM_2500MA;
271 	} else {
272 		reg_val = CHRG_VBUS_ILIM_3000MA;
273 		inlmt = ILIM_3000MA;
274 	}
275 
276 	reg_val = (val & ~CHRG_VBUS_ILIM_MASK)
277 			| (reg_val << CHRG_VBUS_ILIM_BIT_POS);
278 	ret = regmap_write(info->regmap, AXP20X_CHRG_BAK_CTRL, reg_val);
279 	if (ret >= 0)
280 		info->inlmt = inlmt;
281 	else
282 		dev_err(&info->pdev->dev, "charger BAK control %d\n", ret);
283 
284 
285 set_inlmt_fail:
286 	return ret;
287 }
288 
axp288_charger_vbus_path_select(struct axp288_chrg_info * info,bool enable)289 static int axp288_charger_vbus_path_select(struct axp288_chrg_info *info,
290 								bool enable)
291 {
292 	int ret;
293 
294 	if (enable)
295 		ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT,
296 					VBUS_ISPOUT_VBUS_PATH_DIS, 0);
297 	else
298 		ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT,
299 			VBUS_ISPOUT_VBUS_PATH_DIS, VBUS_ISPOUT_VBUS_PATH_DIS);
300 
301 	if (ret < 0)
302 		dev_err(&info->pdev->dev, "axp288 vbus path select %d\n", ret);
303 
304 
305 	return ret;
306 }
307 
axp288_charger_enable_charger(struct axp288_chrg_info * info,bool enable)308 static int axp288_charger_enable_charger(struct axp288_chrg_info *info,
309 								bool enable)
310 {
311 	int ret;
312 
313 	if (enable)
314 		ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1,
315 				CHRG_CCCV_CHG_EN, CHRG_CCCV_CHG_EN);
316 	else
317 		ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1,
318 				CHRG_CCCV_CHG_EN, 0);
319 	if (ret < 0)
320 		dev_err(&info->pdev->dev, "axp288 enable charger %d\n", ret);
321 	else
322 		info->is_charger_enabled = enable;
323 
324 	return ret;
325 }
326 
axp288_charger_is_present(struct axp288_chrg_info * info)327 static int axp288_charger_is_present(struct axp288_chrg_info *info)
328 {
329 	int ret, present = 0;
330 	unsigned int val;
331 
332 	ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
333 	if (ret < 0)
334 		return ret;
335 
336 	if (val & PS_STAT_VBUS_PRESENT)
337 		present = 1;
338 	return present;
339 }
340 
axp288_charger_is_online(struct axp288_chrg_info * info)341 static int axp288_charger_is_online(struct axp288_chrg_info *info)
342 {
343 	int ret, online = 0;
344 	unsigned int val;
345 
346 	ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
347 	if (ret < 0)
348 		return ret;
349 
350 	if (val & PS_STAT_VBUS_VALID)
351 		online = 1;
352 	return online;
353 }
354 
axp288_get_charger_health(struct axp288_chrg_info * info)355 static int axp288_get_charger_health(struct axp288_chrg_info *info)
356 {
357 	int ret, pwr_stat, chrg_stat;
358 	int health = POWER_SUPPLY_HEALTH_UNKNOWN;
359 	unsigned int val;
360 
361 	ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
362 	if ((ret < 0) || !(val & PS_STAT_VBUS_PRESENT))
363 		goto health_read_fail;
364 	else
365 		pwr_stat = val;
366 
367 	ret = regmap_read(info->regmap, AXP20X_PWR_OP_MODE, &val);
368 	if (ret < 0)
369 		goto health_read_fail;
370 	else
371 		chrg_stat = val;
372 
373 	if (!(pwr_stat & PS_STAT_VBUS_VALID))
374 		health = POWER_SUPPLY_HEALTH_DEAD;
375 	else if (chrg_stat & CHRG_STAT_PMIC_OTP)
376 		health = POWER_SUPPLY_HEALTH_OVERHEAT;
377 	else if (chrg_stat & CHRG_STAT_BAT_SAFE_MODE)
378 		health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
379 	else
380 		health = POWER_SUPPLY_HEALTH_GOOD;
381 
382 health_read_fail:
383 	return health;
384 }
385 
axp288_charger_usb_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)386 static int axp288_charger_usb_set_property(struct power_supply *psy,
387 				    enum power_supply_property psp,
388 				    const union power_supply_propval *val)
389 {
390 	struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
391 	int ret = 0;
392 	int scaled_val;
393 
394 	mutex_lock(&info->lock);
395 
396 	switch (psp) {
397 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
398 		scaled_val = min(val->intval, info->max_cc);
399 		scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
400 		ret = axp288_charger_set_cc(info, scaled_val);
401 		if (ret < 0)
402 			dev_warn(&info->pdev->dev, "set charge current failed\n");
403 		break;
404 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
405 		scaled_val = min(val->intval, info->max_cv);
406 		scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
407 		ret = axp288_charger_set_cv(info, scaled_val);
408 		if (ret < 0)
409 			dev_warn(&info->pdev->dev, "set charge voltage failed\n");
410 		break;
411 	default:
412 		ret = -EINVAL;
413 	}
414 
415 	mutex_unlock(&info->lock);
416 	return ret;
417 }
418 
axp288_charger_usb_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)419 static int axp288_charger_usb_get_property(struct power_supply *psy,
420 				    enum power_supply_property psp,
421 				    union power_supply_propval *val)
422 {
423 	struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
424 	int ret = 0;
425 
426 	mutex_lock(&info->lock);
427 
428 	switch (psp) {
429 	case POWER_SUPPLY_PROP_PRESENT:
430 		/* Check for OTG case first */
431 		if (info->otg.id_short) {
432 			val->intval = 0;
433 			break;
434 		}
435 		ret = axp288_charger_is_present(info);
436 		if (ret < 0)
437 			goto psy_get_prop_fail;
438 		info->present = ret;
439 		val->intval = info->present;
440 		break;
441 	case POWER_SUPPLY_PROP_ONLINE:
442 		/* Check for OTG case first */
443 		if (info->otg.id_short) {
444 			val->intval = 0;
445 			break;
446 		}
447 		ret = axp288_charger_is_online(info);
448 		if (ret < 0)
449 			goto psy_get_prop_fail;
450 		info->online = ret;
451 		val->intval = info->online;
452 		break;
453 	case POWER_SUPPLY_PROP_HEALTH:
454 		val->intval = axp288_get_charger_health(info);
455 		break;
456 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
457 		val->intval = info->cc * 1000;
458 		break;
459 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
460 		val->intval = info->max_cc * 1000;
461 		break;
462 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
463 		val->intval = info->cv * 1000;
464 		break;
465 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
466 		val->intval = info->max_cv * 1000;
467 		break;
468 	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
469 		val->intval = info->inlmt * 1000;
470 		break;
471 	default:
472 		ret = -EINVAL;
473 		goto psy_get_prop_fail;
474 	}
475 
476 psy_get_prop_fail:
477 	mutex_unlock(&info->lock);
478 	return ret;
479 }
480 
axp288_charger_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)481 static int axp288_charger_property_is_writeable(struct power_supply *psy,
482 		enum power_supply_property psp)
483 {
484 	int ret;
485 
486 	switch (psp) {
487 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
488 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
489 		ret = 1;
490 		break;
491 	default:
492 		ret = 0;
493 	}
494 
495 	return ret;
496 }
497 
498 static enum power_supply_property axp288_usb_props[] = {
499 	POWER_SUPPLY_PROP_PRESENT,
500 	POWER_SUPPLY_PROP_ONLINE,
501 	POWER_SUPPLY_PROP_TYPE,
502 	POWER_SUPPLY_PROP_HEALTH,
503 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
504 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
505 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
506 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
507 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
508 };
509 
510 static const struct power_supply_desc axp288_charger_desc = {
511 	.name			= "axp288_charger",
512 	.type			= POWER_SUPPLY_TYPE_USB,
513 	.properties		= axp288_usb_props,
514 	.num_properties		= ARRAY_SIZE(axp288_usb_props),
515 	.get_property		= axp288_charger_usb_get_property,
516 	.set_property		= axp288_charger_usb_set_property,
517 	.property_is_writeable	= axp288_charger_property_is_writeable,
518 };
519 
axp288_charger_irq_thread_handler(int irq,void * dev)520 static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
521 {
522 	struct axp288_chrg_info *info = dev;
523 	int i;
524 
525 	for (i = 0; i < CHRG_INTR_END; i++) {
526 		if (info->irq[i] == irq)
527 			break;
528 	}
529 
530 	if (i >= CHRG_INTR_END) {
531 		dev_warn(&info->pdev->dev, "spurious interrupt!!\n");
532 		return IRQ_NONE;
533 	}
534 
535 	switch (i) {
536 	case VBUS_OV_IRQ:
537 		dev_dbg(&info->pdev->dev, "VBUS Over Voltage INTR\n");
538 		break;
539 	case CHARGE_DONE_IRQ:
540 		dev_dbg(&info->pdev->dev, "Charging Done INTR\n");
541 		break;
542 	case CHARGE_CHARGING_IRQ:
543 		dev_dbg(&info->pdev->dev, "Start Charging IRQ\n");
544 		break;
545 	case BAT_SAFE_QUIT_IRQ:
546 		dev_dbg(&info->pdev->dev,
547 			"Quit Safe Mode(restart timer) Charging IRQ\n");
548 		break;
549 	case BAT_SAFE_ENTER_IRQ:
550 		dev_dbg(&info->pdev->dev,
551 			"Enter Safe Mode(timer expire) Charging IRQ\n");
552 		break;
553 	case QCBTU_IRQ:
554 		dev_dbg(&info->pdev->dev,
555 			"Quit Battery Under Temperature(CHRG) INTR\n");
556 		break;
557 	case CBTU_IRQ:
558 		dev_dbg(&info->pdev->dev,
559 			"Hit Battery Under Temperature(CHRG) INTR\n");
560 		break;
561 	case QCBTO_IRQ:
562 		dev_dbg(&info->pdev->dev,
563 			"Quit Battery Over Temperature(CHRG) INTR\n");
564 		break;
565 	case CBTO_IRQ:
566 		dev_dbg(&info->pdev->dev,
567 			"Hit Battery Over Temperature(CHRG) INTR\n");
568 		break;
569 	default:
570 		dev_warn(&info->pdev->dev, "Spurious Interrupt!!!\n");
571 		goto out;
572 	}
573 
574 	power_supply_changed(info->psy_usb);
575 out:
576 	return IRQ_HANDLED;
577 }
578 
axp288_charger_extcon_evt_worker(struct work_struct * work)579 static void axp288_charger_extcon_evt_worker(struct work_struct *work)
580 {
581 	struct axp288_chrg_info *info =
582 	    container_of(work, struct axp288_chrg_info, cable.work);
583 	int ret, current_limit;
584 	bool changed = false;
585 	struct extcon_dev *edev = info->cable.edev;
586 	bool old_connected = info->cable.connected;
587 
588 	/* Determine cable/charger type */
589 	if (extcon_get_cable_state(edev, AXP288_EXTCON_SLOW_CHARGER) > 0) {
590 		dev_dbg(&info->pdev->dev, "USB SDP charger  is connected");
591 		info->cable.connected = true;
592 		info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
593 	} else if (extcon_get_cable_state(edev,
594 				AXP288_EXTCON_DOWNSTREAM_CHARGER) > 0) {
595 		dev_dbg(&info->pdev->dev, "USB CDP charger is connected");
596 		info->cable.connected = true;
597 		info->cable.chg_type = POWER_SUPPLY_TYPE_USB_CDP;
598 	} else if (extcon_get_cable_state(edev,
599 					AXP288_EXTCON_FAST_CHARGER) > 0) {
600 		dev_dbg(&info->pdev->dev, "USB DCP charger is connected");
601 		info->cable.connected = true;
602 		info->cable.chg_type = POWER_SUPPLY_TYPE_USB_DCP;
603 	} else {
604 		if (old_connected)
605 			dev_dbg(&info->pdev->dev, "USB charger disconnected");
606 		info->cable.connected = false;
607 		info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
608 	}
609 
610 	/* Cable status changed */
611 	if (old_connected != info->cable.connected)
612 		changed = true;
613 
614 	if (!changed)
615 		return;
616 
617 	mutex_lock(&info->lock);
618 
619 	if (info->is_charger_enabled && !info->cable.connected) {
620 		info->enable_charger = false;
621 		ret = axp288_charger_enable_charger(info, info->enable_charger);
622 		if (ret < 0)
623 			dev_err(&info->pdev->dev,
624 				"cannot disable charger (%d)", ret);
625 
626 	} else if (!info->is_charger_enabled && info->cable.connected) {
627 		switch (info->cable.chg_type) {
628 		case POWER_SUPPLY_TYPE_USB:
629 			current_limit = ILIM_500MA;
630 			break;
631 		case POWER_SUPPLY_TYPE_USB_CDP:
632 			current_limit = ILIM_1500MA;
633 			break;
634 		case POWER_SUPPLY_TYPE_USB_DCP:
635 			current_limit = ILIM_2000MA;
636 			break;
637 		default:
638 			/* Unknown */
639 			current_limit = 0;
640 			break;
641 		}
642 
643 		/* Set vbus current limit first, then enable charger */
644 		ret = axp288_charger_set_vbus_inlmt(info, current_limit);
645 		if (ret < 0) {
646 			dev_err(&info->pdev->dev,
647 				"error setting current limit (%d)", ret);
648 		} else {
649 			info->enable_charger = (current_limit > 0);
650 			ret = axp288_charger_enable_charger(info,
651 							info->enable_charger);
652 			if (ret < 0)
653 				dev_err(&info->pdev->dev,
654 					"cannot enable charger (%d)", ret);
655 		}
656 	}
657 
658 	if (changed)
659 		info->health = axp288_get_charger_health(info);
660 
661 	mutex_unlock(&info->lock);
662 
663 	if (changed)
664 		power_supply_changed(info->psy_usb);
665 }
666 
axp288_charger_handle_cable_evt(struct notifier_block * nb,unsigned long event,void * param)667 static int axp288_charger_handle_cable_evt(struct notifier_block *nb,
668 					  unsigned long event, void *param)
669 {
670 	struct axp288_chrg_info *info =
671 	    container_of(nb, struct axp288_chrg_info, cable.nb);
672 
673 	schedule_work(&info->cable.work);
674 
675 	return NOTIFY_OK;
676 }
677 
axp288_charger_otg_evt_worker(struct work_struct * work)678 static void axp288_charger_otg_evt_worker(struct work_struct *work)
679 {
680 	struct axp288_chrg_info *info =
681 	    container_of(work, struct axp288_chrg_info, otg.work);
682 	int ret;
683 
684 	/* Disable VBUS path before enabling the 5V boost */
685 	ret = axp288_charger_vbus_path_select(info, !info->otg.id_short);
686 	if (ret < 0)
687 		dev_warn(&info->pdev->dev, "vbus path disable failed\n");
688 }
689 
axp288_charger_handle_otg_evt(struct notifier_block * nb,unsigned long event,void * param)690 static int axp288_charger_handle_otg_evt(struct notifier_block *nb,
691 				   unsigned long event, void *param)
692 {
693 	struct axp288_chrg_info *info =
694 	    container_of(nb, struct axp288_chrg_info, otg.id_nb);
695 	struct extcon_dev *edev = param;
696 	int usb_host = extcon_get_cable_state(edev, "USB-Host");
697 
698 	dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n",
699 				usb_host ? "attached" : "detached");
700 
701 	/*
702 	 * Set usb_id_short flag to avoid running charger detection logic
703 	 * in case usb host.
704 	 */
705 	info->otg.id_short = usb_host;
706 	schedule_work(&info->otg.work);
707 
708 	return NOTIFY_OK;
709 }
710 
charger_init_hw_regs(struct axp288_chrg_info * info)711 static void charger_init_hw_regs(struct axp288_chrg_info *info)
712 {
713 	int ret, cc, cv;
714 	unsigned int val;
715 
716 	/* Program temperature thresholds */
717 	ret = regmap_write(info->regmap, AXP20X_V_LTF_CHRG, CHRG_VLTFC_0C);
718 	if (ret < 0)
719 		dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
720 							AXP20X_V_LTF_CHRG, ret);
721 
722 	ret = regmap_write(info->regmap, AXP20X_V_HTF_CHRG, CHRG_VHTFC_45C);
723 	if (ret < 0)
724 		dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
725 							AXP20X_V_HTF_CHRG, ret);
726 
727 	/* Do not turn-off charger o/p after charge cycle ends */
728 	ret = regmap_update_bits(info->regmap,
729 				AXP20X_CHRG_CTRL2,
730 				CNTL2_CHG_OUT_TURNON, 1);
731 	if (ret < 0)
732 		dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
733 						AXP20X_CHRG_CTRL2, ret);
734 
735 	/* Enable interrupts */
736 	ret = regmap_update_bits(info->regmap,
737 				AXP20X_IRQ2_EN,
738 				BAT_IRQ_CFG_BAT_MASK, 1);
739 	if (ret < 0)
740 		dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
741 						AXP20X_IRQ2_EN, ret);
742 
743 	ret = regmap_update_bits(info->regmap, AXP20X_IRQ3_EN,
744 				TEMP_IRQ_CFG_MASK, 1);
745 	if (ret < 0)
746 		dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
747 						AXP20X_IRQ3_EN, ret);
748 
749 	/* Setup ending condition for charging to be 10% of I(chrg) */
750 	ret = regmap_update_bits(info->regmap,
751 				AXP20X_CHRG_CTRL1,
752 				CHRG_CCCV_ITERM_20P, 0);
753 	if (ret < 0)
754 		dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
755 						AXP20X_CHRG_CTRL1, ret);
756 
757 	/* Disable OCV-SOC curve calibration */
758 	ret = regmap_update_bits(info->regmap,
759 				AXP20X_CC_CTRL,
760 				FG_CNTL_OCV_ADJ_EN, 0);
761 	if (ret < 0)
762 		dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
763 						AXP20X_CC_CTRL, ret);
764 
765 	/* Init charging current and voltage */
766 	info->max_cc = info->pdata->max_cc;
767 	info->max_cv = info->pdata->max_cv;
768 
769 	/* Read current charge voltage and current limit */
770 	ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val);
771 	if (ret < 0) {
772 		/* Assume default if cannot read */
773 		info->cc = info->pdata->def_cc;
774 		info->cv = info->pdata->def_cv;
775 	} else {
776 		/* Determine charge voltage */
777 		cv = (val & CHRG_CCCV_CV_MASK) >> CHRG_CCCV_CV_BIT_POS;
778 		switch (cv) {
779 		case CHRG_CCCV_CV_4100MV:
780 			info->cv = CV_4100MV;
781 			break;
782 		case CHRG_CCCV_CV_4150MV:
783 			info->cv = CV_4150MV;
784 			break;
785 		case CHRG_CCCV_CV_4200MV:
786 			info->cv = CV_4200MV;
787 			break;
788 		case CHRG_CCCV_CV_4350MV:
789 			info->cv = CV_4350MV;
790 			break;
791 		default:
792 			info->cv = INT_MAX;
793 			break;
794 		}
795 
796 		/* Determine charge current limit */
797 		cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS;
798 		cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET;
799 		info->cc = cc;
800 
801 		/* Program default charging voltage and current */
802 		cc = min(info->pdata->def_cc, info->max_cc);
803 		cv = min(info->pdata->def_cv, info->max_cv);
804 
805 		ret = axp288_charger_set_cc(info, cc);
806 		if (ret < 0)
807 			dev_warn(&info->pdev->dev,
808 					"error(%d) in setting CC\n", ret);
809 
810 		ret = axp288_charger_set_cv(info, cv);
811 		if (ret < 0)
812 			dev_warn(&info->pdev->dev,
813 					"error(%d) in setting CV\n", ret);
814 	}
815 }
816 
axp288_charger_probe(struct platform_device * pdev)817 static int axp288_charger_probe(struct platform_device *pdev)
818 {
819 	int ret, i, pirq;
820 	struct axp288_chrg_info *info;
821 	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
822 	struct power_supply_config charger_cfg = {};
823 
824 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
825 	if (!info)
826 		return -ENOMEM;
827 
828 	info->pdev = pdev;
829 	info->regmap = axp20x->regmap;
830 	info->regmap_irqc = axp20x->regmap_irqc;
831 	info->pdata = pdev->dev.platform_data;
832 
833 	if (!info->pdata) {
834 		/* Try ACPI provided pdata via device properties */
835 		if (!device_property_present(&pdev->dev,
836 						"axp288_charger_data\n"))
837 			dev_err(&pdev->dev, "failed to get platform data\n");
838 		return -ENODEV;
839 	}
840 
841 	info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME);
842 	if (info->cable.edev == NULL) {
843 		dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n",
844 			AXP288_EXTCON_DEV_NAME);
845 		return -EPROBE_DEFER;
846 	}
847 
848 	/* Register for extcon notification */
849 	INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker);
850 	info->cable.nb.notifier_call = axp288_charger_handle_cable_evt;
851 	ret = extcon_register_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
852 	if (ret) {
853 		dev_err(&info->pdev->dev,
854 			"failed to register extcon notifier %d\n", ret);
855 		return ret;
856 	}
857 
858 	platform_set_drvdata(pdev, info);
859 	mutex_init(&info->lock);
860 
861 	/* Register with power supply class */
862 	charger_cfg.drv_data = info;
863 	info->psy_usb = power_supply_register(&pdev->dev, &axp288_charger_desc,
864 						&charger_cfg);
865 	if (IS_ERR(info->psy_usb)) {
866 		dev_err(&pdev->dev, "failed to register power supply charger\n");
867 		ret = PTR_ERR(info->psy_usb);
868 		goto psy_reg_failed;
869 	}
870 
871 	/* Register for OTG notification */
872 	INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker);
873 	info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt;
874 	ret = extcon_register_interest(&info->otg.cable, NULL, "USB-Host",
875 				       &info->otg.id_nb);
876 	if (ret)
877 		dev_warn(&pdev->dev, "failed to register otg notifier\n");
878 
879 	if (info->otg.cable.edev)
880 		info->otg.id_short = extcon_get_cable_state(
881 					info->otg.cable.edev, "USB-Host");
882 
883 	/* Register charger interrupts */
884 	for (i = 0; i < CHRG_INTR_END; i++) {
885 		pirq = platform_get_irq(info->pdev, i);
886 		if (pirq < 0) {
887 			dev_err(&pdev->dev, "Failed to get IRQ: %d\n", pirq);
888 			return pirq;
889 		}
890 		info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
891 		if (info->irq[i] < 0) {
892 			dev_warn(&info->pdev->dev,
893 				"failed to get virtual interrupt=%d\n", pirq);
894 			ret = info->irq[i];
895 			goto intr_reg_failed;
896 		}
897 		ret = devm_request_threaded_irq(&info->pdev->dev, info->irq[i],
898 					NULL, axp288_charger_irq_thread_handler,
899 					IRQF_ONESHOT, info->pdev->name, info);
900 		if (ret) {
901 			dev_err(&pdev->dev, "failed to request interrupt=%d\n",
902 								info->irq[i]);
903 			goto intr_reg_failed;
904 		}
905 	}
906 
907 	charger_init_hw_regs(info);
908 
909 	return 0;
910 
911 intr_reg_failed:
912 	if (info->otg.cable.edev)
913 		extcon_unregister_interest(&info->otg.cable);
914 	power_supply_unregister(info->psy_usb);
915 psy_reg_failed:
916 	extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
917 	return ret;
918 }
919 
axp288_charger_remove(struct platform_device * pdev)920 static int axp288_charger_remove(struct platform_device *pdev)
921 {
922 	struct axp288_chrg_info *info =  dev_get_drvdata(&pdev->dev);
923 
924 	if (info->otg.cable.edev)
925 		extcon_unregister_interest(&info->otg.cable);
926 
927 	extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
928 	power_supply_unregister(info->psy_usb);
929 
930 	return 0;
931 }
932 
933 static struct platform_driver axp288_charger_driver = {
934 	.probe = axp288_charger_probe,
935 	.remove = axp288_charger_remove,
936 	.driver = {
937 		.name = "axp288_charger",
938 	},
939 };
940 
941 module_platform_driver(axp288_charger_driver);
942 
943 MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
944 MODULE_DESCRIPTION("X-power AXP288 Charger Driver");
945 MODULE_LICENSE("GPL v2");
946