Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  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
136enum {
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
149struct 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
187static 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
210static 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
241static 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
285set_inlmt_fail:
286	return ret;
287}
288
289static 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
308static 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
327static 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
341static 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
355static 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
382health_read_fail:
383	return health;
384}
385
386static 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
419static 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
476psy_get_prop_fail:
477	mutex_unlock(&info->lock);
478	return ret;
479}
480
481static 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
498static 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
510static 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
520static 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);
575out:
576	return IRQ_HANDLED;
577}
578
579static 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
667static 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
678static 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
690static 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
711static 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
817static 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		info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
887		if (info->irq[i] < 0) {
888			dev_warn(&info->pdev->dev,
889				"failed to get virtual interrupt=%d\n", pirq);
890			ret = info->irq[i];
891			goto intr_reg_failed;
892		}
893		ret = devm_request_threaded_irq(&info->pdev->dev, info->irq[i],
894					NULL, axp288_charger_irq_thread_handler,
895					IRQF_ONESHOT, info->pdev->name, info);
896		if (ret) {
897			dev_err(&pdev->dev, "failed to request interrupt=%d\n",
898								info->irq[i]);
899			goto intr_reg_failed;
900		}
901	}
902
903	charger_init_hw_regs(info);
904
905	return 0;
906
907intr_reg_failed:
908	if (info->otg.cable.edev)
909		extcon_unregister_interest(&info->otg.cable);
910	power_supply_unregister(info->psy_usb);
911psy_reg_failed:
912	extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
913	return ret;
914}
915
916static int axp288_charger_remove(struct platform_device *pdev)
917{
918	struct axp288_chrg_info *info =  dev_get_drvdata(&pdev->dev);
919
920	if (info->otg.cable.edev)
921		extcon_unregister_interest(&info->otg.cable);
922
923	extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
924	power_supply_unregister(info->psy_usb);
925
926	return 0;
927}
928
929static struct platform_driver axp288_charger_driver = {
930	.probe = axp288_charger_probe,
931	.remove = axp288_charger_remove,
932	.driver = {
933		.name = "axp288_charger",
934	},
935};
936
937module_platform_driver(axp288_charger_driver);
938
939MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
940MODULE_DESCRIPTION("X-power AXP288 Charger Driver");
941MODULE_LICENSE("GPL v2");