xref: /linux/drivers/power/supply/cpcap-charger.c (revision 39196cfe10dd2b46ee28b44abbc0db4f4cb7822f)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20c9888e3STony Lindgren /*
30c9888e3STony Lindgren  * Motorola CPCAP PMIC battery charger driver
40c9888e3STony Lindgren  *
50c9888e3STony Lindgren  * Copyright (C) 2017 Tony Lindgren <tony@atomide.com>
60c9888e3STony Lindgren  *
70c9888e3STony Lindgren  * Rewritten for Linux power framework with some parts based on
80c9888e3STony Lindgren  * on earlier driver found in the Motorola Linux kernel:
90c9888e3STony Lindgren  *
100c9888e3STony Lindgren  * Copyright (C) 2009-2010 Motorola, Inc.
110c9888e3STony Lindgren  */
120c9888e3STony Lindgren 
130c9888e3STony Lindgren #include <linux/atomic.h>
140c9888e3STony Lindgren #include <linux/init.h>
150c9888e3STony Lindgren #include <linux/module.h>
160c9888e3STony Lindgren #include <linux/slab.h>
170c9888e3STony Lindgren #include <linux/err.h>
180c9888e3STony Lindgren #include <linux/interrupt.h>
190c9888e3STony Lindgren #include <linux/notifier.h>
200c9888e3STony Lindgren #include <linux/of.h>
210c9888e3STony Lindgren #include <linux/of_platform.h>
220c9888e3STony Lindgren #include <linux/platform_device.h>
230c9888e3STony Lindgren #include <linux/power_supply.h>
240c9888e3STony Lindgren #include <linux/regmap.h>
250c9888e3STony Lindgren 
260c9888e3STony Lindgren #include <linux/gpio/consumer.h>
270c9888e3STony Lindgren #include <linux/usb/phy_companion.h>
280c9888e3STony Lindgren #include <linux/phy/omap_usb.h>
290c9888e3STony Lindgren #include <linux/usb/otg.h>
300c9888e3STony Lindgren #include <linux/iio/consumer.h>
310c9888e3STony Lindgren #include <linux/mfd/motorola-cpcap.h>
320c9888e3STony Lindgren 
331e45330bSTony Lindgren /*
341e45330bSTony Lindgren  * CPCAP_REG_CRM register bits. For documentation of somewhat similar hardware,
351e45330bSTony Lindgren  * see NXP "MC13783 Power Management and Audio Circuit Users's Guide"
361e45330bSTony Lindgren  * MC13783UG.pdf chapter "8.5 Battery Interface Register Summary". The registers
371e45330bSTony Lindgren  * and values for CPCAP are different, but some of the internal components seem
381e45330bSTony Lindgren  * similar. Also see the Motorola Linux kernel cpcap-regbits.h. CPCAP_REG_CHRGR_1
391e45330bSTony Lindgren  * bits that seem to describe the CRM register.
401e45330bSTony Lindgren  */
410c9888e3STony Lindgren #define CPCAP_REG_CRM_UNUSED_641_15	BIT(15)	/* 641 = register number */
420c9888e3STony Lindgren #define CPCAP_REG_CRM_UNUSED_641_14	BIT(14)	/* 641 = register number */
431e45330bSTony Lindgren #define CPCAP_REG_CRM_CHRG_LED_EN	BIT(13)	/* Charger LED */
441e45330bSTony Lindgren #define CPCAP_REG_CRM_RVRSMODE		BIT(12)	/* USB VBUS output enable */
451e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_TR1		BIT(11)	/* Trickle charge current */
460c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG_TR0		BIT(10)
471e45330bSTony Lindgren #define CPCAP_REG_CRM_FET_OVRD		BIT(9)	/* 0 = hardware, 1 = FET_CTRL */
481e45330bSTony Lindgren #define CPCAP_REG_CRM_FET_CTRL		BIT(8)	/* BPFET 1 if FET_OVRD set */
491e45330bSTony Lindgren #define CPCAP_REG_CRM_VCHRG3		BIT(7)	/* Charge voltage bits */
500c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG2		BIT(6)
510c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG1		BIT(5)
520c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG0		BIT(4)
531e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG3		BIT(3)	/* Charge current bits */
540c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG2		BIT(2)
550c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG1		BIT(1)
560c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG0		BIT(0)
570c9888e3STony Lindgren 
580c9888e3STony Lindgren /* CPCAP_REG_CRM trickle charge voltages */
590c9888e3STony Lindgren #define CPCAP_REG_CRM_TR(val)		(((val) & 0x3) << 10)
600c9888e3STony Lindgren #define CPCAP_REG_CRM_TR_0A00		CPCAP_REG_CRM_TR(0x0)
610c9888e3STony Lindgren #define CPCAP_REG_CRM_TR_0A24		CPCAP_REG_CRM_TR(0x1)
620c9888e3STony Lindgren #define CPCAP_REG_CRM_TR_0A48		CPCAP_REG_CRM_TR(0x2)
630c9888e3STony Lindgren #define CPCAP_REG_CRM_TR_0A72		CPCAP_REG_CRM_TR(0x4)
640c9888e3STony Lindgren 
6570c9fc9aSTony Lindgren /*
6670c9fc9aSTony Lindgren  * CPCAP_REG_CRM charge voltages based on the ADC channel 1 values.
6770c9fc9aSTony Lindgren  * Note that these register bits don't match MC13783UG.pdf VCHRG
6870c9fc9aSTony Lindgren  * register bits.
6970c9fc9aSTony Lindgren  */
700c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG(val)	(((val) & 0xf) << 4)
710c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG_3V80	CPCAP_REG_CRM_VCHRG(0x0)
720c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG_4V10	CPCAP_REG_CRM_VCHRG(0x1)
7370c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V12	CPCAP_REG_CRM_VCHRG(0x2)
7470c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V15	CPCAP_REG_CRM_VCHRG(0x3)
7570c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V17	CPCAP_REG_CRM_VCHRG(0x4)
7670c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V20	CPCAP_REG_CRM_VCHRG(0x5)
7770c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V23	CPCAP_REG_CRM_VCHRG(0x6)
7870c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V25	CPCAP_REG_CRM_VCHRG(0x7)
7970c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V27	CPCAP_REG_CRM_VCHRG(0x8)
8070c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V30	CPCAP_REG_CRM_VCHRG(0x9)
8170c9fc9aSTony Lindgren #define CPCAP_REG_CRM_VCHRG_4V33	CPCAP_REG_CRM_VCHRG(0xa)
823ae5f066STony Lindgren #define CPCAP_REG_CRM_VCHRG_4V35	CPCAP_REG_CRM_VCHRG(0xb)
830c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG_4V38	CPCAP_REG_CRM_VCHRG(0xc)
840c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG_4V40	CPCAP_REG_CRM_VCHRG(0xd)
850c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG_4V42	CPCAP_REG_CRM_VCHRG(0xe)
860c9888e3STony Lindgren #define CPCAP_REG_CRM_VCHRG_4V44	CPCAP_REG_CRM_VCHRG(0xf)
870c9888e3STony Lindgren 
881e45330bSTony Lindgren /*
891e45330bSTony Lindgren  * CPCAP_REG_CRM charge currents. These seem to match MC13783UG.pdf
901e45330bSTony Lindgren  * values in "Table 8-3. Charge Path Regulator Current Limit
911e45330bSTony Lindgren  * Characteristics" for the nominal values.
92c6fdea96SPavel Machek  *
93c6fdea96SPavel Machek  * Except 70mA and 1.596A and unlimited, these are simply 88.7mA / step.
941e45330bSTony Lindgren  */
950c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG(val)	(((val) & 0xf) << 0)
960c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG_0A000	CPCAP_REG_CRM_ICHRG(0x0)
970c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG_0A070	CPCAP_REG_CRM_ICHRG(0x1)
981e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A177	CPCAP_REG_CRM_ICHRG(0x2)
991e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A266	CPCAP_REG_CRM_ICHRG(0x3)
1001e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A355	CPCAP_REG_CRM_ICHRG(0x4)
1011e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A443	CPCAP_REG_CRM_ICHRG(0x5)
1021e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A532	CPCAP_REG_CRM_ICHRG(0x6)
1031e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A621	CPCAP_REG_CRM_ICHRG(0x7)
1041e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A709	CPCAP_REG_CRM_ICHRG(0x8)
1051e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A798	CPCAP_REG_CRM_ICHRG(0x9)
1061e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A886	CPCAP_REG_CRM_ICHRG(0xa)
1071e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_0A975	CPCAP_REG_CRM_ICHRG(0xb)
1081e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_1A064	CPCAP_REG_CRM_ICHRG(0xc)
1091e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_1A152	CPCAP_REG_CRM_ICHRG(0xd)
1101e45330bSTony Lindgren #define CPCAP_REG_CRM_ICHRG_1A596	CPCAP_REG_CRM_ICHRG(0xe)
1110c9888e3STony Lindgren #define CPCAP_REG_CRM_ICHRG_NO_LIMIT	CPCAP_REG_CRM_ICHRG(0xf)
1120c9888e3STony Lindgren 
1137f737861STony Lindgren /* CPCAP_REG_VUSBC register bits needed for VBUS */
1147f737861STony Lindgren #define CPCAP_BIT_VBUS_SWITCH		BIT(0)	/* VBUS boost to 5V */
1157f737861STony Lindgren 
1160c9888e3STony Lindgren enum {
1170c9888e3STony Lindgren 	CPCAP_CHARGER_IIO_BATTDET,
1180c9888e3STony Lindgren 	CPCAP_CHARGER_IIO_VOLTAGE,
1190c9888e3STony Lindgren 	CPCAP_CHARGER_IIO_VBUS,
1200c9888e3STony Lindgren 	CPCAP_CHARGER_IIO_CHRG_CURRENT,
1210c9888e3STony Lindgren 	CPCAP_CHARGER_IIO_BATT_CURRENT,
1220c9888e3STony Lindgren 	CPCAP_CHARGER_IIO_NR,
1230c9888e3STony Lindgren };
1240c9888e3STony Lindgren 
1250c9888e3STony Lindgren struct cpcap_charger_ddata {
1260c9888e3STony Lindgren 	struct device *dev;
1270c9888e3STony Lindgren 	struct regmap *reg;
1280c9888e3STony Lindgren 	struct list_head irq_list;
1290c9888e3STony Lindgren 	struct delayed_work detect_work;
1300c9888e3STony Lindgren 	struct delayed_work vbus_work;
1310c9888e3STony Lindgren 	struct gpio_desc *gpio[2];		/* gpio_reven0 & 1 */
1320c9888e3STony Lindgren 
1330c9888e3STony Lindgren 	struct iio_channel *channels[CPCAP_CHARGER_IIO_NR];
1340c9888e3STony Lindgren 
1350c9888e3STony Lindgren 	struct power_supply *usb;
1360c9888e3STony Lindgren 
1370c9888e3STony Lindgren 	struct phy_companion comparator;	/* For USB VBUS */
1387f737861STony Lindgren 	unsigned int vbus_enabled:1;
1397f737861STony Lindgren 	unsigned int feeding_vbus:1;
1400c9888e3STony Lindgren 	atomic_t active;
1410c9888e3STony Lindgren 
1420c9888e3STony Lindgren 	int status;
143d4ee021cSTony Lindgren 	int voltage;
144c6fdea96SPavel Machek 	int limit_current;
1450c9888e3STony Lindgren };
1460c9888e3STony Lindgren 
1470c9888e3STony Lindgren struct cpcap_interrupt_desc {
1480c9888e3STony Lindgren 	int irq;
1490c9888e3STony Lindgren 	struct list_head node;
1500c9888e3STony Lindgren 	const char *name;
1510c9888e3STony Lindgren };
1520c9888e3STony Lindgren 
1530c9888e3STony Lindgren struct cpcap_charger_ints_state {
1540c9888e3STony Lindgren 	bool chrg_det;
1550c9888e3STony Lindgren 	bool rvrs_chrg;
1560c9888e3STony Lindgren 	bool vbusov;
1570c9888e3STony Lindgren 
1580c9888e3STony Lindgren 	bool chrg_se1b;
1590c9888e3STony Lindgren 	bool rvrs_mode;
160d4ee021cSTony Lindgren 	bool chrgcurr2;
1610c9888e3STony Lindgren 	bool chrgcurr1;
1620c9888e3STony Lindgren 	bool vbusvld;
1630c9888e3STony Lindgren 
1640c9888e3STony Lindgren 	bool battdetb;
1650c9888e3STony Lindgren };
1660c9888e3STony Lindgren 
1670c9888e3STony Lindgren static enum power_supply_property cpcap_charger_props[] = {
1680c9888e3STony Lindgren 	POWER_SUPPLY_PROP_STATUS,
1690c9888e3STony Lindgren 	POWER_SUPPLY_PROP_ONLINE,
1705688ea04STony Lindgren 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
171c6fdea96SPavel Machek 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
1720c9888e3STony Lindgren 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
1730c9888e3STony Lindgren 	POWER_SUPPLY_PROP_CURRENT_NOW,
1740c9888e3STony Lindgren };
1750c9888e3STony Lindgren 
17650fc99f8STony Lindgren /* No battery always shows temperature of -40000 */
1770c9888e3STony Lindgren static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata)
1780c9888e3STony Lindgren {
1790c9888e3STony Lindgren 	struct iio_channel *channel;
18050fc99f8STony Lindgren 	int error, temperature;
1810c9888e3STony Lindgren 
1820c9888e3STony Lindgren 	channel = ddata->channels[CPCAP_CHARGER_IIO_BATTDET];
18350fc99f8STony Lindgren 	error = iio_read_channel_processed(channel, &temperature);
1840c9888e3STony Lindgren 	if (error < 0) {
1850c9888e3STony Lindgren 		dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
1860c9888e3STony Lindgren 
1870c9888e3STony Lindgren 		return false;
1880c9888e3STony Lindgren 	}
1890c9888e3STony Lindgren 
19050fc99f8STony Lindgren 	return temperature > -20000 && temperature < 60000;
1910c9888e3STony Lindgren }
1920c9888e3STony Lindgren 
1930c9888e3STony Lindgren static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata)
1940c9888e3STony Lindgren {
1950c9888e3STony Lindgren 	struct iio_channel *channel;
1960c9888e3STony Lindgren 	int error, value = 0;
1970c9888e3STony Lindgren 
1980c9888e3STony Lindgren 	channel = ddata->channels[CPCAP_CHARGER_IIO_VOLTAGE];
1990c9888e3STony Lindgren 	error = iio_read_channel_processed(channel, &value);
2000c9888e3STony Lindgren 	if (error < 0) {
2010c9888e3STony Lindgren 		dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
2020c9888e3STony Lindgren 
2030c9888e3STony Lindgren 		return 0;
2040c9888e3STony Lindgren 	}
2050c9888e3STony Lindgren 
2060c9888e3STony Lindgren 	return value;
2070c9888e3STony Lindgren }
2080c9888e3STony Lindgren 
2090c9888e3STony Lindgren static int cpcap_charger_get_charge_current(struct cpcap_charger_ddata *ddata)
2100c9888e3STony Lindgren {
2110c9888e3STony Lindgren 	struct iio_channel *channel;
2120c9888e3STony Lindgren 	int error, value = 0;
2130c9888e3STony Lindgren 
2140c9888e3STony Lindgren 	channel = ddata->channels[CPCAP_CHARGER_IIO_CHRG_CURRENT];
2150c9888e3STony Lindgren 	error = iio_read_channel_processed(channel, &value);
2160c9888e3STony Lindgren 	if (error < 0) {
2170c9888e3STony Lindgren 		dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
2180c9888e3STony Lindgren 
2190c9888e3STony Lindgren 		return 0;
2200c9888e3STony Lindgren 	}
2210c9888e3STony Lindgren 
2220c9888e3STony Lindgren 	return value;
2230c9888e3STony Lindgren }
2240c9888e3STony Lindgren 
2250c9888e3STony Lindgren static int cpcap_charger_get_property(struct power_supply *psy,
2260c9888e3STony Lindgren 				      enum power_supply_property psp,
2270c9888e3STony Lindgren 				      union power_supply_propval *val)
2280c9888e3STony Lindgren {
2290c9888e3STony Lindgren 	struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent);
2300c9888e3STony Lindgren 
2310c9888e3STony Lindgren 	switch (psp) {
2320c9888e3STony Lindgren 	case POWER_SUPPLY_PROP_STATUS:
2330c9888e3STony Lindgren 		val->intval = ddata->status;
2340c9888e3STony Lindgren 		break;
235c6fdea96SPavel Machek 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
236c6fdea96SPavel Machek 		val->intval = ddata->limit_current;
237c6fdea96SPavel Machek 		break;
2385688ea04STony Lindgren 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
2395688ea04STony Lindgren 		val->intval = ddata->voltage;
2405688ea04STony Lindgren 		break;
2410c9888e3STony Lindgren 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2420c9888e3STony Lindgren 		if (ddata->status == POWER_SUPPLY_STATUS_CHARGING)
2430c9888e3STony Lindgren 			val->intval = cpcap_charger_get_charge_voltage(ddata) *
2440c9888e3STony Lindgren 				1000;
2450c9888e3STony Lindgren 		else
2460c9888e3STony Lindgren 			val->intval = 0;
2470c9888e3STony Lindgren 		break;
2480c9888e3STony Lindgren 	case POWER_SUPPLY_PROP_CURRENT_NOW:
2490c9888e3STony Lindgren 		if (ddata->status == POWER_SUPPLY_STATUS_CHARGING)
2500c9888e3STony Lindgren 			val->intval = cpcap_charger_get_charge_current(ddata) *
2510c9888e3STony Lindgren 				1000;
2520c9888e3STony Lindgren 		else
2530c9888e3STony Lindgren 			val->intval = 0;
2540c9888e3STony Lindgren 		break;
2550c9888e3STony Lindgren 	case POWER_SUPPLY_PROP_ONLINE:
2560c9888e3STony Lindgren 		val->intval = ddata->status == POWER_SUPPLY_STATUS_CHARGING;
2570c9888e3STony Lindgren 		break;
2580c9888e3STony Lindgren 	default:
2590c9888e3STony Lindgren 		return -EINVAL;
2600c9888e3STony Lindgren 	}
2610c9888e3STony Lindgren 
2620c9888e3STony Lindgren 	return 0;
2630c9888e3STony Lindgren }
2640c9888e3STony Lindgren 
2655688ea04STony Lindgren static int cpcap_charger_match_voltage(int voltage)
2665688ea04STony Lindgren {
2675688ea04STony Lindgren 	switch (voltage) {
2685688ea04STony Lindgren 	case 0 ... 4100000 - 1: return 3800000;
2695688ea04STony Lindgren 	case 4100000 ... 4120000 - 1: return 4100000;
2705688ea04STony Lindgren 	case 4120000 ... 4150000 - 1: return 4120000;
2715688ea04STony Lindgren 	case 4150000 ... 4170000 - 1: return 4150000;
2725688ea04STony Lindgren 	case 4170000 ... 4200000 - 1: return 4170000;
2735688ea04STony Lindgren 	case 4200000 ... 4230000 - 1: return 4200000;
2745688ea04STony Lindgren 	case 4230000 ... 4250000 - 1: return 4230000;
2755688ea04STony Lindgren 	case 4250000 ... 4270000 - 1: return 4250000;
2765688ea04STony Lindgren 	case 4270000 ... 4300000 - 1: return 4270000;
2775688ea04STony Lindgren 	case 4300000 ... 4330000 - 1: return 4300000;
2785688ea04STony Lindgren 	case 4330000 ... 4350000 - 1: return 4330000;
2795688ea04STony Lindgren 	case 4350000 ... 4380000 - 1: return 4350000;
2805688ea04STony Lindgren 	case 4380000 ... 4400000 - 1: return 4380000;
2815688ea04STony Lindgren 	case 4400000 ... 4420000 - 1: return 4400000;
2825688ea04STony Lindgren 	case 4420000 ... 4440000 - 1: return 4420000;
2835688ea04STony Lindgren 	case 4440000: return 4440000;
2845688ea04STony Lindgren 	default: return 0;
2855688ea04STony Lindgren 	}
2865688ea04STony Lindgren }
2875688ea04STony Lindgren 
2885688ea04STony Lindgren static int
2895688ea04STony Lindgren cpcap_charger_get_bat_const_charge_voltage(struct cpcap_charger_ddata *ddata)
2905688ea04STony Lindgren {
2915688ea04STony Lindgren 	union power_supply_propval prop;
2925688ea04STony Lindgren 	struct power_supply *battery;
2935688ea04STony Lindgren 	int voltage = ddata->voltage;
2945688ea04STony Lindgren 	int error;
2955688ea04STony Lindgren 
2965688ea04STony Lindgren 	battery = power_supply_get_by_name("battery");
2975688ea04STony Lindgren 	if (battery) {
2985688ea04STony Lindgren 		error = power_supply_get_property(battery,
2995688ea04STony Lindgren 				POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
3005688ea04STony Lindgren 				&prop);
3015688ea04STony Lindgren 		if (!error)
3025688ea04STony Lindgren 			voltage = prop.intval;
30339196cfeSColin Ian King 
3044bff91bbSTony Lindgren 		power_supply_put(battery);
30539196cfeSColin Ian King 	}
3065688ea04STony Lindgren 
3075688ea04STony Lindgren 	return voltage;
3085688ea04STony Lindgren }
3095688ea04STony Lindgren 
310c6fdea96SPavel Machek static int cpcap_charger_current_to_regval(int microamp)
311c6fdea96SPavel Machek {
312c6fdea96SPavel Machek 	int miliamp = microamp / 1000;
313c6fdea96SPavel Machek 	int res;
314c6fdea96SPavel Machek 
315c6fdea96SPavel Machek 	if (miliamp < 0)
316c6fdea96SPavel Machek 		return -EINVAL;
317c6fdea96SPavel Machek 	if (miliamp < 70)
318c6fdea96SPavel Machek 		return CPCAP_REG_CRM_ICHRG(0x0);
319c6fdea96SPavel Machek 	if (miliamp < 177)
320c6fdea96SPavel Machek 		return CPCAP_REG_CRM_ICHRG(0x1);
321c6fdea96SPavel Machek 	if (miliamp > 1596)
322c6fdea96SPavel Machek 		return CPCAP_REG_CRM_ICHRG(0xe);
323c6fdea96SPavel Machek 
324c6fdea96SPavel Machek 	res = microamp / 88666;
325c6fdea96SPavel Machek 	if (res > 0xd)
326c6fdea96SPavel Machek 		res = 0xd;
327c6fdea96SPavel Machek 	return CPCAP_REG_CRM_ICHRG(res);
328c6fdea96SPavel Machek }
329c6fdea96SPavel Machek 
3305688ea04STony Lindgren static int cpcap_charger_set_property(struct power_supply *psy,
3315688ea04STony Lindgren 				      enum power_supply_property psp,
3325688ea04STony Lindgren 				      const union power_supply_propval *val)
3335688ea04STony Lindgren {
3345688ea04STony Lindgren 	struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent);
3355688ea04STony Lindgren 	int voltage, batvolt;
3365688ea04STony Lindgren 
3375688ea04STony Lindgren 	switch (psp) {
338c6fdea96SPavel Machek 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
339c6fdea96SPavel Machek 		if (cpcap_charger_current_to_regval(val->intval) < 0)
340c6fdea96SPavel Machek 			return -EINVAL;
341c6fdea96SPavel Machek 		ddata->limit_current = val->intval;
342c6fdea96SPavel Machek 		schedule_delayed_work(&ddata->detect_work, 0);
343c6fdea96SPavel Machek 		break;
3445688ea04STony Lindgren 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3455688ea04STony Lindgren 		voltage = cpcap_charger_match_voltage(val->intval);
3465688ea04STony Lindgren 		batvolt = cpcap_charger_get_bat_const_charge_voltage(ddata);
3475688ea04STony Lindgren 		if (voltage > batvolt)
3485688ea04STony Lindgren 			voltage = batvolt;
3495688ea04STony Lindgren 		ddata->voltage = voltage;
3505688ea04STony Lindgren 		schedule_delayed_work(&ddata->detect_work, 0);
3515688ea04STony Lindgren 		break;
3525688ea04STony Lindgren 	default:
3535688ea04STony Lindgren 		return -EINVAL;
3545688ea04STony Lindgren 	}
3555688ea04STony Lindgren 
3565688ea04STony Lindgren 	return 0;
3575688ea04STony Lindgren }
3585688ea04STony Lindgren 
3595688ea04STony Lindgren static int cpcap_charger_property_is_writeable(struct power_supply *psy,
3605688ea04STony Lindgren 					       enum power_supply_property psp)
3615688ea04STony Lindgren {
3625688ea04STony Lindgren 	switch (psp) {
363c6fdea96SPavel Machek 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
3645688ea04STony Lindgren 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3655688ea04STony Lindgren 		return 1;
3665688ea04STony Lindgren 	default:
3675688ea04STony Lindgren 		return 0;
3685688ea04STony Lindgren 	}
3695688ea04STony Lindgren }
3705688ea04STony Lindgren 
3710c9888e3STony Lindgren static void cpcap_charger_set_cable_path(struct cpcap_charger_ddata *ddata,
3720c9888e3STony Lindgren 					 bool enabled)
3730c9888e3STony Lindgren {
3740c9888e3STony Lindgren 	if (!ddata->gpio[0])
3750c9888e3STony Lindgren 		return;
3760c9888e3STony Lindgren 
3770c9888e3STony Lindgren 	gpiod_set_value(ddata->gpio[0], enabled);
3780c9888e3STony Lindgren }
3790c9888e3STony Lindgren 
3800c9888e3STony Lindgren static void cpcap_charger_set_inductive_path(struct cpcap_charger_ddata *ddata,
3810c9888e3STony Lindgren 					     bool enabled)
3820c9888e3STony Lindgren {
3830c9888e3STony Lindgren 	if (!ddata->gpio[1])
3840c9888e3STony Lindgren 		return;
3850c9888e3STony Lindgren 
3860c9888e3STony Lindgren 	gpiod_set_value(ddata->gpio[1], enabled);
3870c9888e3STony Lindgren }
3880c9888e3STony Lindgren 
3895a214892STony Lindgren static void cpcap_charger_update_state(struct cpcap_charger_ddata *ddata,
3905a214892STony Lindgren 				       int state)
3915a214892STony Lindgren {
3925a214892STony Lindgren 	const char *status;
3935a214892STony Lindgren 
3945a214892STony Lindgren 	if (state > POWER_SUPPLY_STATUS_FULL) {
3955a214892STony Lindgren 		dev_warn(ddata->dev, "unknown state: %i\n", state);
3965a214892STony Lindgren 
3975a214892STony Lindgren 		return;
3985a214892STony Lindgren 	}
3995a214892STony Lindgren 
4005a214892STony Lindgren 	ddata->status = state;
4015a214892STony Lindgren 
4025a214892STony Lindgren 	switch (state) {
4035a214892STony Lindgren 	case POWER_SUPPLY_STATUS_DISCHARGING:
4045a214892STony Lindgren 		status = "DISCONNECTED";
4055a214892STony Lindgren 		break;
4065a214892STony Lindgren 	case POWER_SUPPLY_STATUS_NOT_CHARGING:
4075a214892STony Lindgren 		status = "DETECTING";
4085a214892STony Lindgren 		break;
4095a214892STony Lindgren 	case POWER_SUPPLY_STATUS_CHARGING:
4105a214892STony Lindgren 		status = "CHARGING";
4115a214892STony Lindgren 		break;
4125a214892STony Lindgren 	case POWER_SUPPLY_STATUS_FULL:
4135a214892STony Lindgren 		status = "DONE";
4145a214892STony Lindgren 		break;
4155a214892STony Lindgren 	default:
4165a214892STony Lindgren 		return;
4175a214892STony Lindgren 	}
4185a214892STony Lindgren 
4195a214892STony Lindgren 	dev_dbg(ddata->dev, "state: %s\n", status);
4205a214892STony Lindgren }
4215a214892STony Lindgren 
4226ddcec58STony Lindgren static int cpcap_charger_disable(struct cpcap_charger_ddata *ddata)
4236ddcec58STony Lindgren {
4246ddcec58STony Lindgren 	int error;
4256ddcec58STony Lindgren 
4266ddcec58STony Lindgren 	error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, 0x3fff,
4276ddcec58STony Lindgren 				   CPCAP_REG_CRM_FET_OVRD |
4286ddcec58STony Lindgren 				   CPCAP_REG_CRM_FET_CTRL);
4296ddcec58STony Lindgren 	if (error)
4306ddcec58STony Lindgren 		dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
4316ddcec58STony Lindgren 
4326ddcec58STony Lindgren 	return error;
4336ddcec58STony Lindgren }
4346ddcec58STony Lindgren 
4356ddcec58STony Lindgren static int cpcap_charger_enable(struct cpcap_charger_ddata *ddata,
4360c9888e3STony Lindgren 				int max_voltage, int charge_current,
4370c9888e3STony Lindgren 				int trickle_current)
4380c9888e3STony Lindgren {
4390c9888e3STony Lindgren 	int error;
4400c9888e3STony Lindgren 
4416ddcec58STony Lindgren 	if (!max_voltage || !charge_current)
4426ddcec58STony Lindgren 		return -EINVAL;
4430c9888e3STony Lindgren 
4446ddcec58STony Lindgren 	dev_dbg(ddata->dev, "enable: %i %i %i\n",
4456ddcec58STony Lindgren 		max_voltage, charge_current, trickle_current);
4460c9888e3STony Lindgren 
4470c9888e3STony Lindgren 	error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, 0x3fff,
4480c9888e3STony Lindgren 				   CPCAP_REG_CRM_CHRG_LED_EN |
4490c9888e3STony Lindgren 				   trickle_current |
4500c9888e3STony Lindgren 				   CPCAP_REG_CRM_FET_OVRD |
4510c9888e3STony Lindgren 				   CPCAP_REG_CRM_FET_CTRL |
4520c9888e3STony Lindgren 				   max_voltage |
4530c9888e3STony Lindgren 				   charge_current);
4546ddcec58STony Lindgren 	if (error)
4550c9888e3STony Lindgren 		dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
4560c9888e3STony Lindgren 
4570c9888e3STony Lindgren 	return error;
4580c9888e3STony Lindgren }
4590c9888e3STony Lindgren 
4600c9888e3STony Lindgren static bool cpcap_charger_vbus_valid(struct cpcap_charger_ddata *ddata)
4610c9888e3STony Lindgren {
4620c9888e3STony Lindgren 	int error, value = 0;
4630c9888e3STony Lindgren 	struct iio_channel *channel =
4640c9888e3STony Lindgren 		ddata->channels[CPCAP_CHARGER_IIO_VBUS];
4650c9888e3STony Lindgren 
4660c9888e3STony Lindgren 	error = iio_read_channel_processed(channel, &value);
4670c9888e3STony Lindgren 	if (error >= 0)
4680c9888e3STony Lindgren 		return value > 3900 ? true : false;
4690c9888e3STony Lindgren 
4700c9888e3STony Lindgren 	dev_err(ddata->dev, "error reading VBUS: %i\n", error);
4710c9888e3STony Lindgren 
4720c9888e3STony Lindgren 	return false;
4730c9888e3STony Lindgren }
4740c9888e3STony Lindgren 
4750c9888e3STony Lindgren /* VBUS control functions for the USB PHY companion */
4760c9888e3STony Lindgren static void cpcap_charger_vbus_work(struct work_struct *work)
4770c9888e3STony Lindgren {
4780c9888e3STony Lindgren 	struct cpcap_charger_ddata *ddata;
4790c9888e3STony Lindgren 	bool vbus = false;
4800c9888e3STony Lindgren 	int error;
4810c9888e3STony Lindgren 
4820c9888e3STony Lindgren 	ddata = container_of(work, struct cpcap_charger_ddata,
4830c9888e3STony Lindgren 			     vbus_work.work);
4840c9888e3STony Lindgren 
4850c9888e3STony Lindgren 	if (ddata->vbus_enabled) {
4860c9888e3STony Lindgren 		vbus = cpcap_charger_vbus_valid(ddata);
4870c9888e3STony Lindgren 		if (vbus) {
488e015964aSTony Lindgren 			dev_dbg(ddata->dev, "VBUS already provided\n");
4890c9888e3STony Lindgren 
4900c9888e3STony Lindgren 			return;
4910c9888e3STony Lindgren 		}
4920c9888e3STony Lindgren 
4937f737861STony Lindgren 		ddata->feeding_vbus = true;
4940c9888e3STony Lindgren 		cpcap_charger_set_cable_path(ddata, false);
4950c9888e3STony Lindgren 		cpcap_charger_set_inductive_path(ddata, false);
4960c9888e3STony Lindgren 
4976ddcec58STony Lindgren 		error = cpcap_charger_disable(ddata);
4980c9888e3STony Lindgren 		if (error)
4990c9888e3STony Lindgren 			goto out_err;
5000c9888e3STony Lindgren 
5016ddcec58STony Lindgren 		cpcap_charger_update_state(ddata,
5026ddcec58STony Lindgren 					   POWER_SUPPLY_STATUS_DISCHARGING);
5036ddcec58STony Lindgren 
5047f737861STony Lindgren 		error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC,
5057f737861STony Lindgren 					   CPCAP_BIT_VBUS_SWITCH,
5067f737861STony Lindgren 					   CPCAP_BIT_VBUS_SWITCH);
5077f737861STony Lindgren 		if (error)
5087f737861STony Lindgren 			goto out_err;
5097f737861STony Lindgren 
5100c9888e3STony Lindgren 		error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM,
5110c9888e3STony Lindgren 					   CPCAP_REG_CRM_RVRSMODE,
5120c9888e3STony Lindgren 					   CPCAP_REG_CRM_RVRSMODE);
5130c9888e3STony Lindgren 		if (error)
5140c9888e3STony Lindgren 			goto out_err;
5150c9888e3STony Lindgren 	} else {
5167f737861STony Lindgren 		error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC,
5177f737861STony Lindgren 					   CPCAP_BIT_VBUS_SWITCH, 0);
5187f737861STony Lindgren 		if (error)
5197f737861STony Lindgren 			goto out_err;
5207f737861STony Lindgren 
5210c9888e3STony Lindgren 		error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM,
5220c9888e3STony Lindgren 					   CPCAP_REG_CRM_RVRSMODE, 0);
5230c9888e3STony Lindgren 		if (error)
5240c9888e3STony Lindgren 			goto out_err;
5250c9888e3STony Lindgren 
5260c9888e3STony Lindgren 		cpcap_charger_set_cable_path(ddata, true);
5270c9888e3STony Lindgren 		cpcap_charger_set_inductive_path(ddata, true);
5287f737861STony Lindgren 		ddata->feeding_vbus = false;
5290c9888e3STony Lindgren 	}
5300c9888e3STony Lindgren 
5310c9888e3STony Lindgren 	return;
5320c9888e3STony Lindgren 
5330c9888e3STony Lindgren out_err:
5346ddcec58STony Lindgren 	cpcap_charger_update_state(ddata, POWER_SUPPLY_STATUS_UNKNOWN);
5350c9888e3STony Lindgren 	dev_err(ddata->dev, "%s could not %s vbus: %i\n", __func__,
5360c9888e3STony Lindgren 		ddata->vbus_enabled ? "enable" : "disable", error);
5370c9888e3STony Lindgren }
5380c9888e3STony Lindgren 
5390c9888e3STony Lindgren static int cpcap_charger_set_vbus(struct phy_companion *comparator,
5400c9888e3STony Lindgren 				  bool enabled)
5410c9888e3STony Lindgren {
5420c9888e3STony Lindgren 	struct cpcap_charger_ddata *ddata =
5430c9888e3STony Lindgren 		container_of(comparator, struct cpcap_charger_ddata,
5440c9888e3STony Lindgren 			     comparator);
5450c9888e3STony Lindgren 
5460c9888e3STony Lindgren 	ddata->vbus_enabled = enabled;
5470c9888e3STony Lindgren 	schedule_delayed_work(&ddata->vbus_work, 0);
5480c9888e3STony Lindgren 
5490c9888e3STony Lindgren 	return 0;
5500c9888e3STony Lindgren }
5510c9888e3STony Lindgren 
5520c9888e3STony Lindgren /* Charger interrupt handling functions */
5530c9888e3STony Lindgren 
5540c9888e3STony Lindgren static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,
5550c9888e3STony Lindgren 					struct cpcap_charger_ints_state *s)
5560c9888e3STony Lindgren {
5570c9888e3STony Lindgren 	int val, error;
5580c9888e3STony Lindgren 
5590c9888e3STony Lindgren 	error = regmap_read(ddata->reg, CPCAP_REG_INTS1, &val);
5600c9888e3STony Lindgren 	if (error)
5610c9888e3STony Lindgren 		return error;
5620c9888e3STony Lindgren 
5630c9888e3STony Lindgren 	s->chrg_det = val & BIT(13);
5640c9888e3STony Lindgren 	s->rvrs_chrg = val & BIT(12);
5650c9888e3STony Lindgren 	s->vbusov = val & BIT(11);
5660c9888e3STony Lindgren 
5670c9888e3STony Lindgren 	error = regmap_read(ddata->reg, CPCAP_REG_INTS2, &val);
5680c9888e3STony Lindgren 	if (error)
5690c9888e3STony Lindgren 		return error;
5700c9888e3STony Lindgren 
5710c9888e3STony Lindgren 	s->chrg_se1b = val & BIT(13);
5720c9888e3STony Lindgren 	s->rvrs_mode = val & BIT(6);
573d4ee021cSTony Lindgren 	s->chrgcurr2 = val & BIT(5);
5740c9888e3STony Lindgren 	s->chrgcurr1 = val & BIT(4);
5750c9888e3STony Lindgren 	s->vbusvld = val & BIT(3);
5760c9888e3STony Lindgren 
5770c9888e3STony Lindgren 	error = regmap_read(ddata->reg, CPCAP_REG_INTS4, &val);
5780c9888e3STony Lindgren 	if (error)
5790c9888e3STony Lindgren 		return error;
5800c9888e3STony Lindgren 
5810c9888e3STony Lindgren 	s->battdetb = val & BIT(6);
5820c9888e3STony Lindgren 
5830c9888e3STony Lindgren 	return 0;
5840c9888e3STony Lindgren }
5850c9888e3STony Lindgren 
586e3da2ce0Skbuild test robot static int cpcap_charger_voltage_to_regval(int voltage)
587d4ee021cSTony Lindgren {
588d4ee021cSTony Lindgren 	int offset;
589d4ee021cSTony Lindgren 
590d4ee021cSTony Lindgren 	switch (voltage) {
591d4ee021cSTony Lindgren 	case 0 ... 4100000 - 1:
592d4ee021cSTony Lindgren 		return 0;
593d4ee021cSTony Lindgren 	case 4100000 ... 4200000 - 1:
594d4ee021cSTony Lindgren 		offset = 1;
595d4ee021cSTony Lindgren 		break;
596d4ee021cSTony Lindgren 	case 4200000 ... 4300000 - 1:
597d4ee021cSTony Lindgren 		offset = 0;
598d4ee021cSTony Lindgren 		break;
599d4ee021cSTony Lindgren 	case 4300000 ... 4380000 - 1:
600d4ee021cSTony Lindgren 		offset = -1;
601d4ee021cSTony Lindgren 		break;
602d4ee021cSTony Lindgren 	case 4380000 ... 4440000:
603d4ee021cSTony Lindgren 		offset = -2;
604d4ee021cSTony Lindgren 		break;
605d4ee021cSTony Lindgren 	default:
606d4ee021cSTony Lindgren 		return 0;
607d4ee021cSTony Lindgren 	}
608d4ee021cSTony Lindgren 
609d4ee021cSTony Lindgren 	return ((voltage - 4100000) / 20000) + offset;
610d4ee021cSTony Lindgren }
611d4ee021cSTony Lindgren 
612d4ee021cSTony Lindgren static void cpcap_charger_disconnect(struct cpcap_charger_ddata *ddata,
613d4ee021cSTony Lindgren 				     int state, unsigned long delay)
614d4ee021cSTony Lindgren {
615d4ee021cSTony Lindgren 	int error;
616d4ee021cSTony Lindgren 
6172071236bSTony Lindgren 	/* Update battery state before disconnecting the charger */
6182071236bSTony Lindgren 	switch (state) {
6192071236bSTony Lindgren 	case POWER_SUPPLY_STATUS_DISCHARGING:
6202071236bSTony Lindgren 	case POWER_SUPPLY_STATUS_FULL:
6212071236bSTony Lindgren 		power_supply_changed(ddata->usb);
6222071236bSTony Lindgren 		break;
6232071236bSTony Lindgren 	default:
6242071236bSTony Lindgren 		break;
6252071236bSTony Lindgren 	}
6262071236bSTony Lindgren 
6276ddcec58STony Lindgren 	error = cpcap_charger_disable(ddata);
6286ddcec58STony Lindgren 	if (error) {
6296ddcec58STony Lindgren 		cpcap_charger_update_state(ddata, POWER_SUPPLY_STATUS_UNKNOWN);
630d4ee021cSTony Lindgren 		return;
6316ddcec58STony Lindgren 	}
632d4ee021cSTony Lindgren 
633d4ee021cSTony Lindgren 	cpcap_charger_update_state(ddata, state);
634d4ee021cSTony Lindgren 	power_supply_changed(ddata->usb);
635d4ee021cSTony Lindgren 	schedule_delayed_work(&ddata->detect_work, delay);
636d4ee021cSTony Lindgren }
637d4ee021cSTony Lindgren 
6380c9888e3STony Lindgren static void cpcap_usb_detect(struct work_struct *work)
6390c9888e3STony Lindgren {
6400c9888e3STony Lindgren 	struct cpcap_charger_ddata *ddata;
6410c9888e3STony Lindgren 	struct cpcap_charger_ints_state s;
6422071236bSTony Lindgren 	int error, new_state;
6430c9888e3STony Lindgren 
6440c9888e3STony Lindgren 	ddata = container_of(work, struct cpcap_charger_ddata,
6450c9888e3STony Lindgren 			     detect_work.work);
6460c9888e3STony Lindgren 
6470c9888e3STony Lindgren 	error = cpcap_charger_get_ints_state(ddata, &s);
6480c9888e3STony Lindgren 	if (error)
6490c9888e3STony Lindgren 		return;
6500c9888e3STony Lindgren 
651d4ee021cSTony Lindgren 	/* Just init the state if a charger is connected with no chrg_det set */
652d4ee021cSTony Lindgren 	if (!s.chrg_det && s.chrgcurr1 && s.vbusvld) {
65341ac23f5STony Lindgren 		cpcap_charger_update_state(ddata,
65441ac23f5STony Lindgren 					   POWER_SUPPLY_STATUS_NOT_CHARGING);
655d4ee021cSTony Lindgren 
656d4ee021cSTony Lindgren 		return;
657d4ee021cSTony Lindgren 	}
658d4ee021cSTony Lindgren 
659d4ee021cSTony Lindgren 	/*
660d4ee021cSTony Lindgren 	 * If battery voltage is higher than charge voltage, it may have been
661d4ee021cSTony Lindgren 	 * charged to 4.35V by Android. Try again in 10 minutes.
662d4ee021cSTony Lindgren 	 */
663d4ee021cSTony Lindgren 	if (cpcap_charger_get_charge_voltage(ddata) > ddata->voltage) {
66441ac23f5STony Lindgren 		cpcap_charger_disconnect(ddata,
66541ac23f5STony Lindgren 					 POWER_SUPPLY_STATUS_NOT_CHARGING,
666d4ee021cSTony Lindgren 					 HZ * 60 * 10);
667d4ee021cSTony Lindgren 
668d4ee021cSTony Lindgren 		return;
669d4ee021cSTony Lindgren 	}
670d4ee021cSTony Lindgren 
671d4ee021cSTony Lindgren 	/* Throttle chrgcurr2 interrupt for charger done and retry */
6725a214892STony Lindgren 	switch (ddata->status) {
67341ac23f5STony Lindgren 	case POWER_SUPPLY_STATUS_CHARGING:
674d4ee021cSTony Lindgren 		if (s.chrgcurr2)
675d4ee021cSTony Lindgren 			break;
6762071236bSTony Lindgren 		new_state = POWER_SUPPLY_STATUS_FULL;
6772071236bSTony Lindgren 
678d4ee021cSTony Lindgren 		if (s.chrgcurr1 && s.vbusvld) {
6792071236bSTony Lindgren 			cpcap_charger_disconnect(ddata, new_state, HZ * 5);
680d4ee021cSTony Lindgren 			return;
681d4ee021cSTony Lindgren 		}
682d4ee021cSTony Lindgren 		break;
68341ac23f5STony Lindgren 	case POWER_SUPPLY_STATUS_FULL:
684d4ee021cSTony Lindgren 		if (!s.chrgcurr2)
685d4ee021cSTony Lindgren 			break;
6862071236bSTony Lindgren 		if (s.vbusvld)
6872071236bSTony Lindgren 			new_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
6882071236bSTony Lindgren 		else
6892071236bSTony Lindgren 			new_state = POWER_SUPPLY_STATUS_DISCHARGING;
6902071236bSTony Lindgren 
6912071236bSTony Lindgren 		cpcap_charger_disconnect(ddata, new_state, HZ * 5);
6922071236bSTony Lindgren 
693d4ee021cSTony Lindgren 		return;
694d4ee021cSTony Lindgren 	default:
695d4ee021cSTony Lindgren 		break;
696d4ee021cSTony Lindgren 	}
697d4ee021cSTony Lindgren 
6987f737861STony Lindgren 	if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
6997f737861STony Lindgren 	    s.chrgcurr1) {
700c6fdea96SPavel Machek 		int max_current = 532000;
701c6fdea96SPavel Machek 		int vchrg, ichrg;
7020c9888e3STony Lindgren 
7030c9888e3STony Lindgren 		if (cpcap_charger_battery_found(ddata))
704c6fdea96SPavel Machek 			max_current = 1596000;
7050c9888e3STony Lindgren 
706c6fdea96SPavel Machek 		if (max_current > ddata->limit_current)
707c6fdea96SPavel Machek 			max_current = ddata->limit_current;
708c6fdea96SPavel Machek 
709c6fdea96SPavel Machek 		ichrg = cpcap_charger_current_to_regval(max_current);
710d4ee021cSTony Lindgren 		vchrg = cpcap_charger_voltage_to_regval(ddata->voltage);
7116ddcec58STony Lindgren 		error = cpcap_charger_enable(ddata,
712d4ee021cSTony Lindgren 					     CPCAP_REG_CRM_VCHRG(vchrg),
713c6fdea96SPavel Machek 					     ichrg, 0);
7140c9888e3STony Lindgren 		if (error)
7150c9888e3STony Lindgren 			goto out_err;
71641ac23f5STony Lindgren 		cpcap_charger_update_state(ddata,
71741ac23f5STony Lindgren 					   POWER_SUPPLY_STATUS_CHARGING);
7180c9888e3STony Lindgren 	} else {
7196ddcec58STony Lindgren 		error = cpcap_charger_disable(ddata);
7200c9888e3STony Lindgren 		if (error)
7210c9888e3STony Lindgren 			goto out_err;
72241ac23f5STony Lindgren 		cpcap_charger_update_state(ddata,
72341ac23f5STony Lindgren 					   POWER_SUPPLY_STATUS_DISCHARGING);
7240c9888e3STony Lindgren 	}
7250c9888e3STony Lindgren 
726fd10606fSPavel Machek 	power_supply_changed(ddata->usb);
7270c9888e3STony Lindgren 	return;
7280c9888e3STony Lindgren 
7290c9888e3STony Lindgren out_err:
7306ddcec58STony Lindgren 	cpcap_charger_update_state(ddata, POWER_SUPPLY_STATUS_UNKNOWN);
7310c9888e3STony Lindgren 	dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
7320c9888e3STony Lindgren }
7330c9888e3STony Lindgren 
7340c9888e3STony Lindgren static irqreturn_t cpcap_charger_irq_thread(int irq, void *data)
7350c9888e3STony Lindgren {
7360c9888e3STony Lindgren 	struct cpcap_charger_ddata *ddata = data;
7370c9888e3STony Lindgren 
7380c9888e3STony Lindgren 	if (!atomic_read(&ddata->active))
7390c9888e3STony Lindgren 		return IRQ_NONE;
7400c9888e3STony Lindgren 
7410c9888e3STony Lindgren 	schedule_delayed_work(&ddata->detect_work, 0);
7420c9888e3STony Lindgren 
7430c9888e3STony Lindgren 	return IRQ_HANDLED;
7440c9888e3STony Lindgren }
7450c9888e3STony Lindgren 
7460c9888e3STony Lindgren static int cpcap_usb_init_irq(struct platform_device *pdev,
7470c9888e3STony Lindgren 			      struct cpcap_charger_ddata *ddata,
7480c9888e3STony Lindgren 			      const char *name)
7490c9888e3STony Lindgren {
7500c9888e3STony Lindgren 	struct cpcap_interrupt_desc *d;
7510c9888e3STony Lindgren 	int irq, error;
7520c9888e3STony Lindgren 
7530c9888e3STony Lindgren 	irq = platform_get_irq_byname(pdev, name);
754838c8afaSPan Bian 	if (irq < 0)
7550c9888e3STony Lindgren 		return -ENODEV;
7560c9888e3STony Lindgren 
7570c9888e3STony Lindgren 	error = devm_request_threaded_irq(ddata->dev, irq, NULL,
7580c9888e3STony Lindgren 					  cpcap_charger_irq_thread,
759e62333e2STony Lindgren 					  IRQF_SHARED | IRQF_ONESHOT,
7600c9888e3STony Lindgren 					  name, ddata);
7610c9888e3STony Lindgren 	if (error) {
7620c9888e3STony Lindgren 		dev_err(ddata->dev, "could not get irq %s: %i\n",
7630c9888e3STony Lindgren 			name, error);
7640c9888e3STony Lindgren 
7650c9888e3STony Lindgren 		return error;
7660c9888e3STony Lindgren 	}
7670c9888e3STony Lindgren 
7680c9888e3STony Lindgren 	d = devm_kzalloc(ddata->dev, sizeof(*d), GFP_KERNEL);
7690c9888e3STony Lindgren 	if (!d)
7700c9888e3STony Lindgren 		return -ENOMEM;
7710c9888e3STony Lindgren 
7720c9888e3STony Lindgren 	d->name = name;
7730c9888e3STony Lindgren 	d->irq = irq;
7740c9888e3STony Lindgren 	list_add(&d->node, &ddata->irq_list);
7750c9888e3STony Lindgren 
7760c9888e3STony Lindgren 	return 0;
7770c9888e3STony Lindgren }
7780c9888e3STony Lindgren 
7790c9888e3STony Lindgren static const char * const cpcap_charger_irqs[] = {
7800c9888e3STony Lindgren 	/* REG_INT_0 */
7810c9888e3STony Lindgren 	"chrg_det", "rvrs_chrg",
7820c9888e3STony Lindgren 
7830c9888e3STony Lindgren 	/* REG_INT1 */
784d4ee021cSTony Lindgren 	"chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
7850c9888e3STony Lindgren 
7860c9888e3STony Lindgren 	/* REG_INT_3 */
7870c9888e3STony Lindgren 	"battdetb",
7880c9888e3STony Lindgren };
7890c9888e3STony Lindgren 
7900c9888e3STony Lindgren static int cpcap_usb_init_interrupts(struct platform_device *pdev,
7910c9888e3STony Lindgren 				     struct cpcap_charger_ddata *ddata)
7920c9888e3STony Lindgren {
7930c9888e3STony Lindgren 	int i, error;
7940c9888e3STony Lindgren 
7950c9888e3STony Lindgren 	for (i = 0; i < ARRAY_SIZE(cpcap_charger_irqs); i++) {
7960c9888e3STony Lindgren 		error = cpcap_usb_init_irq(pdev, ddata, cpcap_charger_irqs[i]);
7970c9888e3STony Lindgren 		if (error)
7980c9888e3STony Lindgren 			return error;
7990c9888e3STony Lindgren 	}
8000c9888e3STony Lindgren 
8010c9888e3STony Lindgren 	return 0;
8020c9888e3STony Lindgren }
8030c9888e3STony Lindgren 
8040c9888e3STony Lindgren static void cpcap_charger_init_optional_gpios(struct cpcap_charger_ddata *ddata)
8050c9888e3STony Lindgren {
8060c9888e3STony Lindgren 	int i;
8070c9888e3STony Lindgren 
8080c9888e3STony Lindgren 	for (i = 0; i < 2; i++) {
8090c9888e3STony Lindgren 		ddata->gpio[i] = devm_gpiod_get_index(ddata->dev, "mode",
8100c9888e3STony Lindgren 						      i, GPIOD_OUT_HIGH);
8110c9888e3STony Lindgren 		if (IS_ERR(ddata->gpio[i])) {
8120c9888e3STony Lindgren 			dev_info(ddata->dev, "no mode change GPIO%i: %li\n",
8130c9888e3STony Lindgren 				 i, PTR_ERR(ddata->gpio[i]));
8140c9888e3STony Lindgren 			ddata->gpio[i] = NULL;
8150c9888e3STony Lindgren 		}
8160c9888e3STony Lindgren 	}
8170c9888e3STony Lindgren }
8180c9888e3STony Lindgren 
8190c9888e3STony Lindgren static int cpcap_charger_init_iio(struct cpcap_charger_ddata *ddata)
8200c9888e3STony Lindgren {
8210c9888e3STony Lindgren 	const char * const names[CPCAP_CHARGER_IIO_NR] = {
8220c9888e3STony Lindgren 		"battdetb", "battp", "vbus", "chg_isense", "batti",
8230c9888e3STony Lindgren 	};
8240c9888e3STony Lindgren 	int error, i;
8250c9888e3STony Lindgren 
8260c9888e3STony Lindgren 	for (i = 0; i < CPCAP_CHARGER_IIO_NR; i++) {
8270c9888e3STony Lindgren 		ddata->channels[i] = devm_iio_channel_get(ddata->dev,
8280c9888e3STony Lindgren 							  names[i]);
8290c9888e3STony Lindgren 		if (IS_ERR(ddata->channels[i])) {
8300c9888e3STony Lindgren 			error = PTR_ERR(ddata->channels[i]);
8310c9888e3STony Lindgren 			goto out_err;
8320c9888e3STony Lindgren 		}
8330c9888e3STony Lindgren 
8340c9888e3STony Lindgren 		if (!ddata->channels[i]->indio_dev) {
8350c9888e3STony Lindgren 			error = -ENXIO;
8360c9888e3STony Lindgren 			goto out_err;
8370c9888e3STony Lindgren 		}
8380c9888e3STony Lindgren 	}
8390c9888e3STony Lindgren 
8400c9888e3STony Lindgren 	return 0;
8410c9888e3STony Lindgren 
8420c9888e3STony Lindgren out_err:
8437d90fcc1STony Lindgren 	if (error != -EPROBE_DEFER)
8440c9888e3STony Lindgren 		dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
8450c9888e3STony Lindgren 			error);
8460c9888e3STony Lindgren 
8470c9888e3STony Lindgren 	return error;
8480c9888e3STony Lindgren }
8490c9888e3STony Lindgren 
8502071236bSTony Lindgren static char *cpcap_charger_supplied_to[] = {
8512071236bSTony Lindgren 	"battery",
8522071236bSTony Lindgren };
8532071236bSTony Lindgren 
8540c9888e3STony Lindgren static const struct power_supply_desc cpcap_charger_usb_desc = {
8554f700a52STony Lindgren 	.name		= "usb",
8560c9888e3STony Lindgren 	.type		= POWER_SUPPLY_TYPE_USB,
8570c9888e3STony Lindgren 	.properties	= cpcap_charger_props,
8580c9888e3STony Lindgren 	.num_properties	= ARRAY_SIZE(cpcap_charger_props),
8590c9888e3STony Lindgren 	.get_property	= cpcap_charger_get_property,
8605688ea04STony Lindgren 	.set_property	= cpcap_charger_set_property,
8615688ea04STony Lindgren 	.property_is_writeable = cpcap_charger_property_is_writeable,
8620c9888e3STony Lindgren };
8630c9888e3STony Lindgren 
8640c9888e3STony Lindgren #ifdef CONFIG_OF
8650c9888e3STony Lindgren static const struct of_device_id cpcap_charger_id_table[] = {
8660c9888e3STony Lindgren 	{
8670c9888e3STony Lindgren 		.compatible = "motorola,mapphone-cpcap-charger",
8680c9888e3STony Lindgren 	},
8690c9888e3STony Lindgren 	{},
8700c9888e3STony Lindgren };
8710c9888e3STony Lindgren MODULE_DEVICE_TABLE(of, cpcap_charger_id_table);
8720c9888e3STony Lindgren #endif
8730c9888e3STony Lindgren 
8740c9888e3STony Lindgren static int cpcap_charger_probe(struct platform_device *pdev)
8750c9888e3STony Lindgren {
8760c9888e3STony Lindgren 	struct cpcap_charger_ddata *ddata;
8770c9888e3STony Lindgren 	const struct of_device_id *of_id;
878fc443138STony Lindgren 	struct power_supply_config psy_cfg = {};
8790c9888e3STony Lindgren 	int error;
8800c9888e3STony Lindgren 
8810c9888e3STony Lindgren 	of_id = of_match_device(of_match_ptr(cpcap_charger_id_table),
8820c9888e3STony Lindgren 				&pdev->dev);
8830c9888e3STony Lindgren 	if (!of_id)
8840c9888e3STony Lindgren 		return -EINVAL;
8850c9888e3STony Lindgren 
8860c9888e3STony Lindgren 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
8870c9888e3STony Lindgren 	if (!ddata)
8880c9888e3STony Lindgren 		return -ENOMEM;
8890c9888e3STony Lindgren 
8900c9888e3STony Lindgren 	ddata->dev = &pdev->dev;
891d4ee021cSTony Lindgren 	ddata->voltage = 4200000;
892c6fdea96SPavel Machek 	ddata->limit_current = 532000;
8930c9888e3STony Lindgren 
8940c9888e3STony Lindgren 	ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
8950c9888e3STony Lindgren 	if (!ddata->reg)
8960c9888e3STony Lindgren 		return -ENODEV;
8970c9888e3STony Lindgren 
8980c9888e3STony Lindgren 	INIT_LIST_HEAD(&ddata->irq_list);
8990c9888e3STony Lindgren 	INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect);
9000c9888e3STony Lindgren 	INIT_DELAYED_WORK(&ddata->vbus_work, cpcap_charger_vbus_work);
9010c9888e3STony Lindgren 	platform_set_drvdata(pdev, ddata);
9020c9888e3STony Lindgren 
9030c9888e3STony Lindgren 	error = cpcap_charger_init_iio(ddata);
9040c9888e3STony Lindgren 	if (error)
9050c9888e3STony Lindgren 		return error;
9060c9888e3STony Lindgren 
9070c9888e3STony Lindgren 	atomic_set(&ddata->active, 1);
9080c9888e3STony Lindgren 
909fc443138STony Lindgren 	psy_cfg.of_node = pdev->dev.of_node;
910fc443138STony Lindgren 	psy_cfg.drv_data = ddata;
9112071236bSTony Lindgren 	psy_cfg.supplied_to = cpcap_charger_supplied_to;
9122071236bSTony Lindgren 	psy_cfg.num_supplicants = ARRAY_SIZE(cpcap_charger_supplied_to),
913fc443138STony Lindgren 
9140c9888e3STony Lindgren 	ddata->usb = devm_power_supply_register(ddata->dev,
9150c9888e3STony Lindgren 						&cpcap_charger_usb_desc,
916fc443138STony Lindgren 						&psy_cfg);
9170c9888e3STony Lindgren 	if (IS_ERR(ddata->usb)) {
9180c9888e3STony Lindgren 		error = PTR_ERR(ddata->usb);
9190c9888e3STony Lindgren 		dev_err(ddata->dev, "failed to register USB charger: %i\n",
9200c9888e3STony Lindgren 			error);
9210c9888e3STony Lindgren 
9220c9888e3STony Lindgren 		return error;
9230c9888e3STony Lindgren 	}
9240c9888e3STony Lindgren 
9250c9888e3STony Lindgren 	error = cpcap_usb_init_interrupts(pdev, ddata);
9260c9888e3STony Lindgren 	if (error)
9270c9888e3STony Lindgren 		return error;
9280c9888e3STony Lindgren 
9290c9888e3STony Lindgren 	ddata->comparator.set_vbus = cpcap_charger_set_vbus;
9300c9888e3STony Lindgren 	error = omap_usb2_set_comparator(&ddata->comparator);
9310c9888e3STony Lindgren 	if (error == -ENODEV) {
9320c9888e3STony Lindgren 		dev_info(ddata->dev, "charger needs phy, deferring probe\n");
9330c9888e3STony Lindgren 		return -EPROBE_DEFER;
9340c9888e3STony Lindgren 	}
9350c9888e3STony Lindgren 
9360c9888e3STony Lindgren 	cpcap_charger_init_optional_gpios(ddata);
9370c9888e3STony Lindgren 
9380c9888e3STony Lindgren 	schedule_delayed_work(&ddata->detect_work, 0);
9390c9888e3STony Lindgren 
9400c9888e3STony Lindgren 	return 0;
9410c9888e3STony Lindgren }
9420c9888e3STony Lindgren 
9432828ffc2STony Lindgren static void cpcap_charger_shutdown(struct platform_device *pdev)
9440c9888e3STony Lindgren {
9450c9888e3STony Lindgren 	struct cpcap_charger_ddata *ddata = platform_get_drvdata(pdev);
9460c9888e3STony Lindgren 	int error;
9470c9888e3STony Lindgren 
9480c9888e3STony Lindgren 	atomic_set(&ddata->active, 0);
9490c9888e3STony Lindgren 	error = omap_usb2_set_comparator(NULL);
9500c9888e3STony Lindgren 	if (error)
9510c9888e3STony Lindgren 		dev_warn(ddata->dev, "could not clear USB comparator: %i\n",
9520c9888e3STony Lindgren 			 error);
9530c9888e3STony Lindgren 
9546ddcec58STony Lindgren 	error = cpcap_charger_disable(ddata);
9556ddcec58STony Lindgren 	if (error) {
9566ddcec58STony Lindgren 		cpcap_charger_update_state(ddata, POWER_SUPPLY_STATUS_UNKNOWN);
9570c9888e3STony Lindgren 		dev_warn(ddata->dev, "could not clear charger: %i\n",
9580c9888e3STony Lindgren 			 error);
9596ddcec58STony Lindgren 	}
9606ddcec58STony Lindgren 	cpcap_charger_update_state(ddata, POWER_SUPPLY_STATUS_DISCHARGING);
9610c9888e3STony Lindgren 	cancel_delayed_work_sync(&ddata->vbus_work);
9620c9888e3STony Lindgren 	cancel_delayed_work_sync(&ddata->detect_work);
9632828ffc2STony Lindgren }
9642828ffc2STony Lindgren 
9652828ffc2STony Lindgren static int cpcap_charger_remove(struct platform_device *pdev)
9662828ffc2STony Lindgren {
9672828ffc2STony Lindgren 	cpcap_charger_shutdown(pdev);
9680c9888e3STony Lindgren 
9690c9888e3STony Lindgren 	return 0;
9700c9888e3STony Lindgren }
9710c9888e3STony Lindgren 
9720c9888e3STony Lindgren static struct platform_driver cpcap_charger_driver = {
9730c9888e3STony Lindgren 	.probe = cpcap_charger_probe,
9740c9888e3STony Lindgren 	.driver	= {
9750c9888e3STony Lindgren 		.name	= "cpcap-charger",
9760c9888e3STony Lindgren 		.of_match_table = of_match_ptr(cpcap_charger_id_table),
9770c9888e3STony Lindgren 	},
9782828ffc2STony Lindgren 	.shutdown = cpcap_charger_shutdown,
9790c9888e3STony Lindgren 	.remove	= cpcap_charger_remove,
9800c9888e3STony Lindgren };
9810c9888e3STony Lindgren module_platform_driver(cpcap_charger_driver);
9820c9888e3STony Lindgren 
9830c9888e3STony Lindgren MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
9840c9888e3STony Lindgren MODULE_DESCRIPTION("CPCAP Battery Charger Interface driver");
9850c9888e3STony Lindgren MODULE_LICENSE("GPL v2");
9860c9888e3STony Lindgren MODULE_ALIAS("platform:cpcap-charger");
987