xref: /OK3568_Linux_fs/kernel/drivers/power/supply/cpcap-charger.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Motorola CPCAP PMIC battery charger driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2017 Tony Lindgren <tony@atomide.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Rewritten for Linux power framework with some parts based on
8*4882a593Smuzhiyun  * on earlier driver found in the Motorola Linux kernel:
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Copyright (C) 2009-2010 Motorola, Inc.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/atomic.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/err.h>
18*4882a593Smuzhiyun #include <linux/interrupt.h>
19*4882a593Smuzhiyun #include <linux/notifier.h>
20*4882a593Smuzhiyun #include <linux/of.h>
21*4882a593Smuzhiyun #include <linux/of_platform.h>
22*4882a593Smuzhiyun #include <linux/platform_device.h>
23*4882a593Smuzhiyun #include <linux/power_supply.h>
24*4882a593Smuzhiyun #include <linux/regmap.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
27*4882a593Smuzhiyun #include <linux/usb/phy_companion.h>
28*4882a593Smuzhiyun #include <linux/phy/omap_usb.h>
29*4882a593Smuzhiyun #include <linux/usb/otg.h>
30*4882a593Smuzhiyun #include <linux/iio/consumer.h>
31*4882a593Smuzhiyun #include <linux/mfd/motorola-cpcap.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun  * CPCAP_REG_CRM register bits. For documentation of somewhat similar hardware,
35*4882a593Smuzhiyun  * see NXP "MC13783 Power Management and Audio Circuit Users's Guide"
36*4882a593Smuzhiyun  * MC13783UG.pdf chapter "8.5 Battery Interface Register Summary". The registers
37*4882a593Smuzhiyun  * and values for CPCAP are different, but some of the internal components seem
38*4882a593Smuzhiyun  * similar. Also see the Motorola Linux kernel cpcap-regbits.h. CPCAP_REG_CHRGR_1
39*4882a593Smuzhiyun  * bits that seem to describe the CRM register.
40*4882a593Smuzhiyun  */
41*4882a593Smuzhiyun #define CPCAP_REG_CRM_UNUSED_641_15	BIT(15)	/* 641 = register number */
42*4882a593Smuzhiyun #define CPCAP_REG_CRM_UNUSED_641_14	BIT(14)	/* 641 = register number */
43*4882a593Smuzhiyun #define CPCAP_REG_CRM_CHRG_LED_EN	BIT(13)	/* Charger LED */
44*4882a593Smuzhiyun #define CPCAP_REG_CRM_RVRSMODE		BIT(12)	/* USB VBUS output enable */
45*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_TR1		BIT(11)	/* Trickle charge current */
46*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_TR0		BIT(10)
47*4882a593Smuzhiyun #define CPCAP_REG_CRM_FET_OVRD		BIT(9)	/* 0 = hardware, 1 = FET_CTRL */
48*4882a593Smuzhiyun #define CPCAP_REG_CRM_FET_CTRL		BIT(8)	/* BPFET 1 if FET_OVRD set */
49*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG3		BIT(7)	/* Charge voltage bits */
50*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG2		BIT(6)
51*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG1		BIT(5)
52*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG0		BIT(4)
53*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG3		BIT(3)	/* Charge current bits */
54*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG2		BIT(2)
55*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG1		BIT(1)
56*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG0		BIT(0)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /* CPCAP_REG_CRM trickle charge voltages */
59*4882a593Smuzhiyun #define CPCAP_REG_CRM_TR(val)		(((val) & 0x3) << 10)
60*4882a593Smuzhiyun #define CPCAP_REG_CRM_TR_0A00		CPCAP_REG_CRM_TR(0x0)
61*4882a593Smuzhiyun #define CPCAP_REG_CRM_TR_0A24		CPCAP_REG_CRM_TR(0x1)
62*4882a593Smuzhiyun #define CPCAP_REG_CRM_TR_0A48		CPCAP_REG_CRM_TR(0x2)
63*4882a593Smuzhiyun #define CPCAP_REG_CRM_TR_0A72		CPCAP_REG_CRM_TR(0x4)
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun  * CPCAP_REG_CRM charge voltages based on the ADC channel 1 values.
67*4882a593Smuzhiyun  * Note that these register bits don't match MC13783UG.pdf VCHRG
68*4882a593Smuzhiyun  * register bits.
69*4882a593Smuzhiyun  */
70*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG(val)	(((val) & 0xf) << 4)
71*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_3V80	CPCAP_REG_CRM_VCHRG(0x0)
72*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V10	CPCAP_REG_CRM_VCHRG(0x1)
73*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V12	CPCAP_REG_CRM_VCHRG(0x2)
74*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V15	CPCAP_REG_CRM_VCHRG(0x3)
75*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V17	CPCAP_REG_CRM_VCHRG(0x4)
76*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V20	CPCAP_REG_CRM_VCHRG(0x5)
77*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V23	CPCAP_REG_CRM_VCHRG(0x6)
78*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V25	CPCAP_REG_CRM_VCHRG(0x7)
79*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V27	CPCAP_REG_CRM_VCHRG(0x8)
80*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V30	CPCAP_REG_CRM_VCHRG(0x9)
81*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V33	CPCAP_REG_CRM_VCHRG(0xa)
82*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V35	CPCAP_REG_CRM_VCHRG(0xb)
83*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V38	CPCAP_REG_CRM_VCHRG(0xc)
84*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V40	CPCAP_REG_CRM_VCHRG(0xd)
85*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V42	CPCAP_REG_CRM_VCHRG(0xe)
86*4882a593Smuzhiyun #define CPCAP_REG_CRM_VCHRG_4V44	CPCAP_REG_CRM_VCHRG(0xf)
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun  * CPCAP_REG_CRM charge currents. These seem to match MC13783UG.pdf
90*4882a593Smuzhiyun  * values in "Table 8-3. Charge Path Regulator Current Limit
91*4882a593Smuzhiyun  * Characteristics" for the nominal values.
92*4882a593Smuzhiyun  */
93*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG(val)	(((val) & 0xf) << 0)
94*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A000	CPCAP_REG_CRM_ICHRG(0x0)
95*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A070	CPCAP_REG_CRM_ICHRG(0x1)
96*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A177	CPCAP_REG_CRM_ICHRG(0x2)
97*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A266	CPCAP_REG_CRM_ICHRG(0x3)
98*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A355	CPCAP_REG_CRM_ICHRG(0x4)
99*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A443	CPCAP_REG_CRM_ICHRG(0x5)
100*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A532	CPCAP_REG_CRM_ICHRG(0x6)
101*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A621	CPCAP_REG_CRM_ICHRG(0x7)
102*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A709	CPCAP_REG_CRM_ICHRG(0x8)
103*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A798	CPCAP_REG_CRM_ICHRG(0x9)
104*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A886	CPCAP_REG_CRM_ICHRG(0xa)
105*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_0A975	CPCAP_REG_CRM_ICHRG(0xb)
106*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_1A064	CPCAP_REG_CRM_ICHRG(0xc)
107*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_1A152	CPCAP_REG_CRM_ICHRG(0xd)
108*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_1A596	CPCAP_REG_CRM_ICHRG(0xe)
109*4882a593Smuzhiyun #define CPCAP_REG_CRM_ICHRG_NO_LIMIT	CPCAP_REG_CRM_ICHRG(0xf)
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /* CPCAP_REG_VUSBC register bits needed for VBUS */
112*4882a593Smuzhiyun #define CPCAP_BIT_VBUS_SWITCH		BIT(0)	/* VBUS boost to 5V */
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun enum {
115*4882a593Smuzhiyun 	CPCAP_CHARGER_IIO_BATTDET,
116*4882a593Smuzhiyun 	CPCAP_CHARGER_IIO_VOLTAGE,
117*4882a593Smuzhiyun 	CPCAP_CHARGER_IIO_VBUS,
118*4882a593Smuzhiyun 	CPCAP_CHARGER_IIO_CHRG_CURRENT,
119*4882a593Smuzhiyun 	CPCAP_CHARGER_IIO_BATT_CURRENT,
120*4882a593Smuzhiyun 	CPCAP_CHARGER_IIO_NR,
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun enum {
124*4882a593Smuzhiyun 	CPCAP_CHARGER_DISCONNECTED,
125*4882a593Smuzhiyun 	CPCAP_CHARGER_DETECTING,
126*4882a593Smuzhiyun 	CPCAP_CHARGER_CHARGING,
127*4882a593Smuzhiyun 	CPCAP_CHARGER_DONE,
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun struct cpcap_charger_ddata {
131*4882a593Smuzhiyun 	struct device *dev;
132*4882a593Smuzhiyun 	struct regmap *reg;
133*4882a593Smuzhiyun 	struct list_head irq_list;
134*4882a593Smuzhiyun 	struct delayed_work detect_work;
135*4882a593Smuzhiyun 	struct delayed_work vbus_work;
136*4882a593Smuzhiyun 	struct gpio_desc *gpio[2];		/* gpio_reven0 & 1 */
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	struct iio_channel *channels[CPCAP_CHARGER_IIO_NR];
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	struct power_supply *usb;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	struct phy_companion comparator;	/* For USB VBUS */
143*4882a593Smuzhiyun 	unsigned int vbus_enabled:1;
144*4882a593Smuzhiyun 	unsigned int feeding_vbus:1;
145*4882a593Smuzhiyun 	atomic_t active;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	int status;
148*4882a593Smuzhiyun 	int state;
149*4882a593Smuzhiyun 	int voltage;
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun struct cpcap_interrupt_desc {
153*4882a593Smuzhiyun 	int irq;
154*4882a593Smuzhiyun 	struct list_head node;
155*4882a593Smuzhiyun 	const char *name;
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun struct cpcap_charger_ints_state {
159*4882a593Smuzhiyun 	bool chrg_det;
160*4882a593Smuzhiyun 	bool rvrs_chrg;
161*4882a593Smuzhiyun 	bool vbusov;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	bool chrg_se1b;
164*4882a593Smuzhiyun 	bool rvrs_mode;
165*4882a593Smuzhiyun 	bool chrgcurr2;
166*4882a593Smuzhiyun 	bool chrgcurr1;
167*4882a593Smuzhiyun 	bool vbusvld;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	bool battdetb;
170*4882a593Smuzhiyun };
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun static enum power_supply_property cpcap_charger_props[] = {
173*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_STATUS,
174*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ONLINE,
175*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
176*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
177*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_NOW,
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /* No battery always shows temperature of -40000 */
cpcap_charger_battery_found(struct cpcap_charger_ddata * ddata)181*4882a593Smuzhiyun static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct iio_channel *channel;
184*4882a593Smuzhiyun 	int error, temperature;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	channel = ddata->channels[CPCAP_CHARGER_IIO_BATTDET];
187*4882a593Smuzhiyun 	error = iio_read_channel_processed(channel, &temperature);
188*4882a593Smuzhiyun 	if (error < 0) {
189*4882a593Smuzhiyun 		dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		return false;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	return temperature > -20000 && temperature < 60000;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata * ddata)197*4882a593Smuzhiyun static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct iio_channel *channel;
200*4882a593Smuzhiyun 	int error, value = 0;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	channel = ddata->channels[CPCAP_CHARGER_IIO_VOLTAGE];
203*4882a593Smuzhiyun 	error = iio_read_channel_processed(channel, &value);
204*4882a593Smuzhiyun 	if (error < 0) {
205*4882a593Smuzhiyun 		dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		return 0;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	return value;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
cpcap_charger_get_charge_current(struct cpcap_charger_ddata * ddata)213*4882a593Smuzhiyun static int cpcap_charger_get_charge_current(struct cpcap_charger_ddata *ddata)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	struct iio_channel *channel;
216*4882a593Smuzhiyun 	int error, value = 0;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	channel = ddata->channels[CPCAP_CHARGER_IIO_CHRG_CURRENT];
219*4882a593Smuzhiyun 	error = iio_read_channel_processed(channel, &value);
220*4882a593Smuzhiyun 	if (error < 0) {
221*4882a593Smuzhiyun 		dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 		return 0;
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	return value;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
cpcap_charger_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)229*4882a593Smuzhiyun static int cpcap_charger_get_property(struct power_supply *psy,
230*4882a593Smuzhiyun 				      enum power_supply_property psp,
231*4882a593Smuzhiyun 				      union power_supply_propval *val)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	switch (psp) {
236*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
237*4882a593Smuzhiyun 		val->intval = ddata->status;
238*4882a593Smuzhiyun 		break;
239*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
240*4882a593Smuzhiyun 		val->intval = ddata->voltage;
241*4882a593Smuzhiyun 		break;
242*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
243*4882a593Smuzhiyun 		if (ddata->status == POWER_SUPPLY_STATUS_CHARGING)
244*4882a593Smuzhiyun 			val->intval = cpcap_charger_get_charge_voltage(ddata) *
245*4882a593Smuzhiyun 				1000;
246*4882a593Smuzhiyun 		else
247*4882a593Smuzhiyun 			val->intval = 0;
248*4882a593Smuzhiyun 		break;
249*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_NOW:
250*4882a593Smuzhiyun 		if (ddata->status == POWER_SUPPLY_STATUS_CHARGING)
251*4882a593Smuzhiyun 			val->intval = cpcap_charger_get_charge_current(ddata) *
252*4882a593Smuzhiyun 				1000;
253*4882a593Smuzhiyun 		else
254*4882a593Smuzhiyun 			val->intval = 0;
255*4882a593Smuzhiyun 		break;
256*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ONLINE:
257*4882a593Smuzhiyun 		val->intval = ddata->status == POWER_SUPPLY_STATUS_CHARGING;
258*4882a593Smuzhiyun 		break;
259*4882a593Smuzhiyun 	default:
260*4882a593Smuzhiyun 		return -EINVAL;
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return 0;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
cpcap_charger_match_voltage(int voltage)266*4882a593Smuzhiyun static int cpcap_charger_match_voltage(int voltage)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	switch (voltage) {
269*4882a593Smuzhiyun 	case 0 ... 4100000 - 1: return 3800000;
270*4882a593Smuzhiyun 	case 4100000 ... 4120000 - 1: return 4100000;
271*4882a593Smuzhiyun 	case 4120000 ... 4150000 - 1: return 4120000;
272*4882a593Smuzhiyun 	case 4150000 ... 4170000 - 1: return 4150000;
273*4882a593Smuzhiyun 	case 4170000 ... 4200000 - 1: return 4170000;
274*4882a593Smuzhiyun 	case 4200000 ... 4230000 - 1: return 4200000;
275*4882a593Smuzhiyun 	case 4230000 ... 4250000 - 1: return 4230000;
276*4882a593Smuzhiyun 	case 4250000 ... 4270000 - 1: return 4250000;
277*4882a593Smuzhiyun 	case 4270000 ... 4300000 - 1: return 4270000;
278*4882a593Smuzhiyun 	case 4300000 ... 4330000 - 1: return 4300000;
279*4882a593Smuzhiyun 	case 4330000 ... 4350000 - 1: return 4330000;
280*4882a593Smuzhiyun 	case 4350000 ... 4380000 - 1: return 4350000;
281*4882a593Smuzhiyun 	case 4380000 ... 4400000 - 1: return 4380000;
282*4882a593Smuzhiyun 	case 4400000 ... 4420000 - 1: return 4400000;
283*4882a593Smuzhiyun 	case 4420000 ... 4440000 - 1: return 4420000;
284*4882a593Smuzhiyun 	case 4440000: return 4440000;
285*4882a593Smuzhiyun 	default: return 0;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun static int
cpcap_charger_get_bat_const_charge_voltage(struct cpcap_charger_ddata * ddata)290*4882a593Smuzhiyun cpcap_charger_get_bat_const_charge_voltage(struct cpcap_charger_ddata *ddata)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	union power_supply_propval prop;
293*4882a593Smuzhiyun 	struct power_supply *battery;
294*4882a593Smuzhiyun 	int voltage = ddata->voltage;
295*4882a593Smuzhiyun 	int error;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	battery = power_supply_get_by_name("battery");
298*4882a593Smuzhiyun 	if (battery) {
299*4882a593Smuzhiyun 		error = power_supply_get_property(battery,
300*4882a593Smuzhiyun 				POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
301*4882a593Smuzhiyun 				&prop);
302*4882a593Smuzhiyun 		if (!error)
303*4882a593Smuzhiyun 			voltage = prop.intval;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 		power_supply_put(battery);
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return voltage;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
cpcap_charger_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)311*4882a593Smuzhiyun static int cpcap_charger_set_property(struct power_supply *psy,
312*4882a593Smuzhiyun 				      enum power_supply_property psp,
313*4882a593Smuzhiyun 				      const union power_supply_propval *val)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent);
316*4882a593Smuzhiyun 	int voltage, batvolt;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	switch (psp) {
319*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
320*4882a593Smuzhiyun 		voltage = cpcap_charger_match_voltage(val->intval);
321*4882a593Smuzhiyun 		batvolt = cpcap_charger_get_bat_const_charge_voltage(ddata);
322*4882a593Smuzhiyun 		if (voltage > batvolt)
323*4882a593Smuzhiyun 			voltage = batvolt;
324*4882a593Smuzhiyun 		ddata->voltage = voltage;
325*4882a593Smuzhiyun 		schedule_delayed_work(&ddata->detect_work, 0);
326*4882a593Smuzhiyun 		break;
327*4882a593Smuzhiyun 	default:
328*4882a593Smuzhiyun 		return -EINVAL;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	return 0;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
cpcap_charger_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)334*4882a593Smuzhiyun static int cpcap_charger_property_is_writeable(struct power_supply *psy,
335*4882a593Smuzhiyun 					       enum power_supply_property psp)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	switch (psp) {
338*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
339*4882a593Smuzhiyun 		return 1;
340*4882a593Smuzhiyun 	default:
341*4882a593Smuzhiyun 		return 0;
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
cpcap_charger_set_cable_path(struct cpcap_charger_ddata * ddata,bool enabled)345*4882a593Smuzhiyun static void cpcap_charger_set_cable_path(struct cpcap_charger_ddata *ddata,
346*4882a593Smuzhiyun 					 bool enabled)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	if (!ddata->gpio[0])
349*4882a593Smuzhiyun 		return;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	gpiod_set_value(ddata->gpio[0], enabled);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
cpcap_charger_set_inductive_path(struct cpcap_charger_ddata * ddata,bool enabled)354*4882a593Smuzhiyun static void cpcap_charger_set_inductive_path(struct cpcap_charger_ddata *ddata,
355*4882a593Smuzhiyun 					     bool enabled)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	if (!ddata->gpio[1])
358*4882a593Smuzhiyun 		return;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	gpiod_set_value(ddata->gpio[1], enabled);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun 
cpcap_charger_set_state(struct cpcap_charger_ddata * ddata,int max_voltage,int charge_current,int trickle_current)363*4882a593Smuzhiyun static int cpcap_charger_set_state(struct cpcap_charger_ddata *ddata,
364*4882a593Smuzhiyun 				   int max_voltage, int charge_current,
365*4882a593Smuzhiyun 				   int trickle_current)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	bool enable;
368*4882a593Smuzhiyun 	int error;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	enable = (charge_current || trickle_current);
371*4882a593Smuzhiyun 	dev_dbg(ddata->dev, "%s enable: %i\n", __func__, enable);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (!enable) {
374*4882a593Smuzhiyun 		error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM,
375*4882a593Smuzhiyun 					   0x3fff,
376*4882a593Smuzhiyun 					   CPCAP_REG_CRM_FET_OVRD |
377*4882a593Smuzhiyun 					   CPCAP_REG_CRM_FET_CTRL);
378*4882a593Smuzhiyun 		if (error) {
379*4882a593Smuzhiyun 			ddata->status = POWER_SUPPLY_STATUS_UNKNOWN;
380*4882a593Smuzhiyun 			goto out_err;
381*4882a593Smuzhiyun 		}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		ddata->status = POWER_SUPPLY_STATUS_DISCHARGING;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 		return 0;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, 0x3fff,
389*4882a593Smuzhiyun 				   CPCAP_REG_CRM_CHRG_LED_EN |
390*4882a593Smuzhiyun 				   trickle_current |
391*4882a593Smuzhiyun 				   CPCAP_REG_CRM_FET_OVRD |
392*4882a593Smuzhiyun 				   CPCAP_REG_CRM_FET_CTRL |
393*4882a593Smuzhiyun 				   max_voltage |
394*4882a593Smuzhiyun 				   charge_current);
395*4882a593Smuzhiyun 	if (error) {
396*4882a593Smuzhiyun 		ddata->status = POWER_SUPPLY_STATUS_UNKNOWN;
397*4882a593Smuzhiyun 		goto out_err;
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	ddata->status = POWER_SUPPLY_STATUS_CHARGING;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	return 0;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun out_err:
405*4882a593Smuzhiyun 	dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	return error;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
cpcap_charger_vbus_valid(struct cpcap_charger_ddata * ddata)410*4882a593Smuzhiyun static bool cpcap_charger_vbus_valid(struct cpcap_charger_ddata *ddata)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	int error, value = 0;
413*4882a593Smuzhiyun 	struct iio_channel *channel =
414*4882a593Smuzhiyun 		ddata->channels[CPCAP_CHARGER_IIO_VBUS];
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	error = iio_read_channel_processed(channel, &value);
417*4882a593Smuzhiyun 	if (error >= 0)
418*4882a593Smuzhiyun 		return value > 3900 ? true : false;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	dev_err(ddata->dev, "error reading VBUS: %i\n", error);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	return false;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun /* VBUS control functions for the USB PHY companion */
cpcap_charger_vbus_work(struct work_struct * work)426*4882a593Smuzhiyun static void cpcap_charger_vbus_work(struct work_struct *work)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata;
429*4882a593Smuzhiyun 	bool vbus = false;
430*4882a593Smuzhiyun 	int error;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	ddata = container_of(work, struct cpcap_charger_ddata,
433*4882a593Smuzhiyun 			     vbus_work.work);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if (ddata->vbus_enabled) {
436*4882a593Smuzhiyun 		vbus = cpcap_charger_vbus_valid(ddata);
437*4882a593Smuzhiyun 		if (vbus) {
438*4882a593Smuzhiyun 			dev_info(ddata->dev, "VBUS already provided\n");
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 			return;
441*4882a593Smuzhiyun 		}
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 		ddata->feeding_vbus = true;
444*4882a593Smuzhiyun 		cpcap_charger_set_cable_path(ddata, false);
445*4882a593Smuzhiyun 		cpcap_charger_set_inductive_path(ddata, false);
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 		error = cpcap_charger_set_state(ddata, 0, 0, 0);
448*4882a593Smuzhiyun 		if (error)
449*4882a593Smuzhiyun 			goto out_err;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 		error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC,
452*4882a593Smuzhiyun 					   CPCAP_BIT_VBUS_SWITCH,
453*4882a593Smuzhiyun 					   CPCAP_BIT_VBUS_SWITCH);
454*4882a593Smuzhiyun 		if (error)
455*4882a593Smuzhiyun 			goto out_err;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 		error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM,
458*4882a593Smuzhiyun 					   CPCAP_REG_CRM_RVRSMODE,
459*4882a593Smuzhiyun 					   CPCAP_REG_CRM_RVRSMODE);
460*4882a593Smuzhiyun 		if (error)
461*4882a593Smuzhiyun 			goto out_err;
462*4882a593Smuzhiyun 	} else {
463*4882a593Smuzhiyun 		error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC,
464*4882a593Smuzhiyun 					   CPCAP_BIT_VBUS_SWITCH, 0);
465*4882a593Smuzhiyun 		if (error)
466*4882a593Smuzhiyun 			goto out_err;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 		error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM,
469*4882a593Smuzhiyun 					   CPCAP_REG_CRM_RVRSMODE, 0);
470*4882a593Smuzhiyun 		if (error)
471*4882a593Smuzhiyun 			goto out_err;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 		cpcap_charger_set_cable_path(ddata, true);
474*4882a593Smuzhiyun 		cpcap_charger_set_inductive_path(ddata, true);
475*4882a593Smuzhiyun 		ddata->feeding_vbus = false;
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	return;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun out_err:
481*4882a593Smuzhiyun 	dev_err(ddata->dev, "%s could not %s vbus: %i\n", __func__,
482*4882a593Smuzhiyun 		ddata->vbus_enabled ? "enable" : "disable", error);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
cpcap_charger_set_vbus(struct phy_companion * comparator,bool enabled)485*4882a593Smuzhiyun static int cpcap_charger_set_vbus(struct phy_companion *comparator,
486*4882a593Smuzhiyun 				  bool enabled)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata =
489*4882a593Smuzhiyun 		container_of(comparator, struct cpcap_charger_ddata,
490*4882a593Smuzhiyun 			     comparator);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	ddata->vbus_enabled = enabled;
493*4882a593Smuzhiyun 	schedule_delayed_work(&ddata->vbus_work, 0);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	return 0;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun /* Charger interrupt handling functions */
499*4882a593Smuzhiyun 
cpcap_charger_get_ints_state(struct cpcap_charger_ddata * ddata,struct cpcap_charger_ints_state * s)500*4882a593Smuzhiyun static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,
501*4882a593Smuzhiyun 					struct cpcap_charger_ints_state *s)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	int val, error;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	error = regmap_read(ddata->reg, CPCAP_REG_INTS1, &val);
506*4882a593Smuzhiyun 	if (error)
507*4882a593Smuzhiyun 		return error;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	s->chrg_det = val & BIT(13);
510*4882a593Smuzhiyun 	s->rvrs_chrg = val & BIT(12);
511*4882a593Smuzhiyun 	s->vbusov = val & BIT(11);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	error = regmap_read(ddata->reg, CPCAP_REG_INTS2, &val);
514*4882a593Smuzhiyun 	if (error)
515*4882a593Smuzhiyun 		return error;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	s->chrg_se1b = val & BIT(13);
518*4882a593Smuzhiyun 	s->rvrs_mode = val & BIT(6);
519*4882a593Smuzhiyun 	s->chrgcurr2 = val & BIT(5);
520*4882a593Smuzhiyun 	s->chrgcurr1 = val & BIT(4);
521*4882a593Smuzhiyun 	s->vbusvld = val & BIT(3);
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	error = regmap_read(ddata->reg, CPCAP_REG_INTS4, &val);
524*4882a593Smuzhiyun 	if (error)
525*4882a593Smuzhiyun 		return error;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	s->battdetb = val & BIT(6);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	return 0;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun 
cpcap_charger_update_state(struct cpcap_charger_ddata * ddata,int state)532*4882a593Smuzhiyun static void cpcap_charger_update_state(struct cpcap_charger_ddata *ddata,
533*4882a593Smuzhiyun 				       int state)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	const char *status;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	if (state > CPCAP_CHARGER_DONE) {
538*4882a593Smuzhiyun 		dev_warn(ddata->dev, "unknown state: %i\n", state);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 		return;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	ddata->state = state;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	switch (state) {
546*4882a593Smuzhiyun 	case CPCAP_CHARGER_DISCONNECTED:
547*4882a593Smuzhiyun 		status = "DISCONNECTED";
548*4882a593Smuzhiyun 		break;
549*4882a593Smuzhiyun 	case CPCAP_CHARGER_DETECTING:
550*4882a593Smuzhiyun 		status = "DETECTING";
551*4882a593Smuzhiyun 		break;
552*4882a593Smuzhiyun 	case CPCAP_CHARGER_CHARGING:
553*4882a593Smuzhiyun 		status = "CHARGING";
554*4882a593Smuzhiyun 		break;
555*4882a593Smuzhiyun 	case CPCAP_CHARGER_DONE:
556*4882a593Smuzhiyun 		status = "DONE";
557*4882a593Smuzhiyun 		break;
558*4882a593Smuzhiyun 	default:
559*4882a593Smuzhiyun 		return;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	dev_dbg(ddata->dev, "state: %s\n", status);
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun 
cpcap_charger_voltage_to_regval(int voltage)565*4882a593Smuzhiyun static int cpcap_charger_voltage_to_regval(int voltage)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun 	int offset;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	switch (voltage) {
570*4882a593Smuzhiyun 	case 0 ... 4100000 - 1:
571*4882a593Smuzhiyun 		return 0;
572*4882a593Smuzhiyun 	case 4100000 ... 4200000 - 1:
573*4882a593Smuzhiyun 		offset = 1;
574*4882a593Smuzhiyun 		break;
575*4882a593Smuzhiyun 	case 4200000 ... 4300000 - 1:
576*4882a593Smuzhiyun 		offset = 0;
577*4882a593Smuzhiyun 		break;
578*4882a593Smuzhiyun 	case 4300000 ... 4380000 - 1:
579*4882a593Smuzhiyun 		offset = -1;
580*4882a593Smuzhiyun 		break;
581*4882a593Smuzhiyun 	case 4380000 ... 4440000:
582*4882a593Smuzhiyun 		offset = -2;
583*4882a593Smuzhiyun 		break;
584*4882a593Smuzhiyun 	default:
585*4882a593Smuzhiyun 		return 0;
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	return ((voltage - 4100000) / 20000) + offset;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun 
cpcap_charger_disconnect(struct cpcap_charger_ddata * ddata,int state,unsigned long delay)591*4882a593Smuzhiyun static void cpcap_charger_disconnect(struct cpcap_charger_ddata *ddata,
592*4882a593Smuzhiyun 				     int state, unsigned long delay)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun 	int error;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	error = cpcap_charger_set_state(ddata, 0, 0, 0);
597*4882a593Smuzhiyun 	if (error)
598*4882a593Smuzhiyun 		return;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	cpcap_charger_update_state(ddata, state);
601*4882a593Smuzhiyun 	power_supply_changed(ddata->usb);
602*4882a593Smuzhiyun 	schedule_delayed_work(&ddata->detect_work, delay);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
cpcap_usb_detect(struct work_struct * work)605*4882a593Smuzhiyun static void cpcap_usb_detect(struct work_struct *work)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata;
608*4882a593Smuzhiyun 	struct cpcap_charger_ints_state s;
609*4882a593Smuzhiyun 	int error;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	ddata = container_of(work, struct cpcap_charger_ddata,
612*4882a593Smuzhiyun 			     detect_work.work);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	error = cpcap_charger_get_ints_state(ddata, &s);
615*4882a593Smuzhiyun 	if (error)
616*4882a593Smuzhiyun 		return;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	/* Just init the state if a charger is connected with no chrg_det set */
619*4882a593Smuzhiyun 	if (!s.chrg_det && s.chrgcurr1 && s.vbusvld) {
620*4882a593Smuzhiyun 		cpcap_charger_update_state(ddata, CPCAP_CHARGER_DETECTING);
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 		return;
623*4882a593Smuzhiyun 	}
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	/*
626*4882a593Smuzhiyun 	 * If battery voltage is higher than charge voltage, it may have been
627*4882a593Smuzhiyun 	 * charged to 4.35V by Android. Try again in 10 minutes.
628*4882a593Smuzhiyun 	 */
629*4882a593Smuzhiyun 	if (cpcap_charger_get_charge_voltage(ddata) > ddata->voltage) {
630*4882a593Smuzhiyun 		cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DETECTING,
631*4882a593Smuzhiyun 					 HZ * 60 * 10);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 		return;
634*4882a593Smuzhiyun 	}
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	/* Delay for 80ms to avoid vbus bouncing when usb cable is plugged in */
637*4882a593Smuzhiyun 	usleep_range(80000, 120000);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	/* Throttle chrgcurr2 interrupt for charger done and retry */
640*4882a593Smuzhiyun 	switch (ddata->state) {
641*4882a593Smuzhiyun 	case CPCAP_CHARGER_CHARGING:
642*4882a593Smuzhiyun 		if (s.chrgcurr2)
643*4882a593Smuzhiyun 			break;
644*4882a593Smuzhiyun 		if (s.chrgcurr1 && s.vbusvld) {
645*4882a593Smuzhiyun 			cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DONE,
646*4882a593Smuzhiyun 						 HZ * 5);
647*4882a593Smuzhiyun 			return;
648*4882a593Smuzhiyun 		}
649*4882a593Smuzhiyun 		break;
650*4882a593Smuzhiyun 	case CPCAP_CHARGER_DONE:
651*4882a593Smuzhiyun 		if (!s.chrgcurr2)
652*4882a593Smuzhiyun 			break;
653*4882a593Smuzhiyun 		cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DETECTING,
654*4882a593Smuzhiyun 					 HZ * 5);
655*4882a593Smuzhiyun 		return;
656*4882a593Smuzhiyun 	default:
657*4882a593Smuzhiyun 		break;
658*4882a593Smuzhiyun 	}
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
661*4882a593Smuzhiyun 	    s.chrgcurr1) {
662*4882a593Smuzhiyun 		int max_current;
663*4882a593Smuzhiyun 		int vchrg;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 		if (cpcap_charger_battery_found(ddata))
666*4882a593Smuzhiyun 			max_current = CPCAP_REG_CRM_ICHRG_1A596;
667*4882a593Smuzhiyun 		else
668*4882a593Smuzhiyun 			max_current = CPCAP_REG_CRM_ICHRG_0A532;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 		vchrg = cpcap_charger_voltage_to_regval(ddata->voltage);
671*4882a593Smuzhiyun 		error = cpcap_charger_set_state(ddata,
672*4882a593Smuzhiyun 						CPCAP_REG_CRM_VCHRG(vchrg),
673*4882a593Smuzhiyun 						max_current, 0);
674*4882a593Smuzhiyun 		if (error)
675*4882a593Smuzhiyun 			goto out_err;
676*4882a593Smuzhiyun 		cpcap_charger_update_state(ddata, CPCAP_CHARGER_CHARGING);
677*4882a593Smuzhiyun 	} else {
678*4882a593Smuzhiyun 		error = cpcap_charger_set_state(ddata, 0, 0, 0);
679*4882a593Smuzhiyun 		if (error)
680*4882a593Smuzhiyun 			goto out_err;
681*4882a593Smuzhiyun 		cpcap_charger_update_state(ddata, CPCAP_CHARGER_DISCONNECTED);
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	power_supply_changed(ddata->usb);
685*4882a593Smuzhiyun 	return;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun out_err:
688*4882a593Smuzhiyun 	dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
cpcap_charger_irq_thread(int irq,void * data)691*4882a593Smuzhiyun static irqreturn_t cpcap_charger_irq_thread(int irq, void *data)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata = data;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	if (!atomic_read(&ddata->active))
696*4882a593Smuzhiyun 		return IRQ_NONE;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	schedule_delayed_work(&ddata->detect_work, 0);
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	return IRQ_HANDLED;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun 
cpcap_usb_init_irq(struct platform_device * pdev,struct cpcap_charger_ddata * ddata,const char * name)703*4882a593Smuzhiyun static int cpcap_usb_init_irq(struct platform_device *pdev,
704*4882a593Smuzhiyun 			      struct cpcap_charger_ddata *ddata,
705*4882a593Smuzhiyun 			      const char *name)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun 	struct cpcap_interrupt_desc *d;
708*4882a593Smuzhiyun 	int irq, error;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	irq = platform_get_irq_byname(pdev, name);
711*4882a593Smuzhiyun 	if (irq < 0)
712*4882a593Smuzhiyun 		return -ENODEV;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	error = devm_request_threaded_irq(ddata->dev, irq, NULL,
715*4882a593Smuzhiyun 					  cpcap_charger_irq_thread,
716*4882a593Smuzhiyun 					  IRQF_SHARED | IRQF_ONESHOT,
717*4882a593Smuzhiyun 					  name, ddata);
718*4882a593Smuzhiyun 	if (error) {
719*4882a593Smuzhiyun 		dev_err(ddata->dev, "could not get irq %s: %i\n",
720*4882a593Smuzhiyun 			name, error);
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 		return error;
723*4882a593Smuzhiyun 	}
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	d = devm_kzalloc(ddata->dev, sizeof(*d), GFP_KERNEL);
726*4882a593Smuzhiyun 	if (!d)
727*4882a593Smuzhiyun 		return -ENOMEM;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	d->name = name;
730*4882a593Smuzhiyun 	d->irq = irq;
731*4882a593Smuzhiyun 	list_add(&d->node, &ddata->irq_list);
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	return 0;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun static const char * const cpcap_charger_irqs[] = {
737*4882a593Smuzhiyun 	/* REG_INT_0 */
738*4882a593Smuzhiyun 	"chrg_det", "rvrs_chrg",
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	/* REG_INT1 */
741*4882a593Smuzhiyun 	"chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/* REG_INT_3 */
744*4882a593Smuzhiyun 	"battdetb",
745*4882a593Smuzhiyun };
746*4882a593Smuzhiyun 
cpcap_usb_init_interrupts(struct platform_device * pdev,struct cpcap_charger_ddata * ddata)747*4882a593Smuzhiyun static int cpcap_usb_init_interrupts(struct platform_device *pdev,
748*4882a593Smuzhiyun 				     struct cpcap_charger_ddata *ddata)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun 	int i, error;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(cpcap_charger_irqs); i++) {
753*4882a593Smuzhiyun 		error = cpcap_usb_init_irq(pdev, ddata, cpcap_charger_irqs[i]);
754*4882a593Smuzhiyun 		if (error)
755*4882a593Smuzhiyun 			return error;
756*4882a593Smuzhiyun 	}
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	return 0;
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun 
cpcap_charger_init_optional_gpios(struct cpcap_charger_ddata * ddata)761*4882a593Smuzhiyun static void cpcap_charger_init_optional_gpios(struct cpcap_charger_ddata *ddata)
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun 	int i;
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
766*4882a593Smuzhiyun 		ddata->gpio[i] = devm_gpiod_get_index(ddata->dev, "mode",
767*4882a593Smuzhiyun 						      i, GPIOD_OUT_HIGH);
768*4882a593Smuzhiyun 		if (IS_ERR(ddata->gpio[i])) {
769*4882a593Smuzhiyun 			dev_info(ddata->dev, "no mode change GPIO%i: %li\n",
770*4882a593Smuzhiyun 				 i, PTR_ERR(ddata->gpio[i]));
771*4882a593Smuzhiyun 			ddata->gpio[i] = NULL;
772*4882a593Smuzhiyun 		}
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun 
cpcap_charger_init_iio(struct cpcap_charger_ddata * ddata)776*4882a593Smuzhiyun static int cpcap_charger_init_iio(struct cpcap_charger_ddata *ddata)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun 	const char * const names[CPCAP_CHARGER_IIO_NR] = {
779*4882a593Smuzhiyun 		"battdetb", "battp", "vbus", "chg_isense", "batti",
780*4882a593Smuzhiyun 	};
781*4882a593Smuzhiyun 	int error, i;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	for (i = 0; i < CPCAP_CHARGER_IIO_NR; i++) {
784*4882a593Smuzhiyun 		ddata->channels[i] = devm_iio_channel_get(ddata->dev,
785*4882a593Smuzhiyun 							  names[i]);
786*4882a593Smuzhiyun 		if (IS_ERR(ddata->channels[i])) {
787*4882a593Smuzhiyun 			error = PTR_ERR(ddata->channels[i]);
788*4882a593Smuzhiyun 			goto out_err;
789*4882a593Smuzhiyun 		}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 		if (!ddata->channels[i]->indio_dev) {
792*4882a593Smuzhiyun 			error = -ENXIO;
793*4882a593Smuzhiyun 			goto out_err;
794*4882a593Smuzhiyun 		}
795*4882a593Smuzhiyun 	}
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	return 0;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun out_err:
800*4882a593Smuzhiyun 	if (error != -EPROBE_DEFER)
801*4882a593Smuzhiyun 		dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
802*4882a593Smuzhiyun 			error);
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	return error;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun static const struct power_supply_desc cpcap_charger_usb_desc = {
808*4882a593Smuzhiyun 	.name		= "usb",
809*4882a593Smuzhiyun 	.type		= POWER_SUPPLY_TYPE_USB,
810*4882a593Smuzhiyun 	.properties	= cpcap_charger_props,
811*4882a593Smuzhiyun 	.num_properties	= ARRAY_SIZE(cpcap_charger_props),
812*4882a593Smuzhiyun 	.get_property	= cpcap_charger_get_property,
813*4882a593Smuzhiyun 	.set_property	= cpcap_charger_set_property,
814*4882a593Smuzhiyun 	.property_is_writeable = cpcap_charger_property_is_writeable,
815*4882a593Smuzhiyun };
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun #ifdef CONFIG_OF
818*4882a593Smuzhiyun static const struct of_device_id cpcap_charger_id_table[] = {
819*4882a593Smuzhiyun 	{
820*4882a593Smuzhiyun 		.compatible = "motorola,mapphone-cpcap-charger",
821*4882a593Smuzhiyun 	},
822*4882a593Smuzhiyun 	{},
823*4882a593Smuzhiyun };
824*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, cpcap_charger_id_table);
825*4882a593Smuzhiyun #endif
826*4882a593Smuzhiyun 
cpcap_charger_probe(struct platform_device * pdev)827*4882a593Smuzhiyun static int cpcap_charger_probe(struct platform_device *pdev)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata;
830*4882a593Smuzhiyun 	const struct of_device_id *of_id;
831*4882a593Smuzhiyun 	struct power_supply_config psy_cfg = {};
832*4882a593Smuzhiyun 	int error;
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	of_id = of_match_device(of_match_ptr(cpcap_charger_id_table),
835*4882a593Smuzhiyun 				&pdev->dev);
836*4882a593Smuzhiyun 	if (!of_id)
837*4882a593Smuzhiyun 		return -EINVAL;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
840*4882a593Smuzhiyun 	if (!ddata)
841*4882a593Smuzhiyun 		return -ENOMEM;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	ddata->dev = &pdev->dev;
844*4882a593Smuzhiyun 	ddata->voltage = 4200000;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
847*4882a593Smuzhiyun 	if (!ddata->reg)
848*4882a593Smuzhiyun 		return -ENODEV;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ddata->irq_list);
851*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect);
852*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&ddata->vbus_work, cpcap_charger_vbus_work);
853*4882a593Smuzhiyun 	platform_set_drvdata(pdev, ddata);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	error = cpcap_charger_init_iio(ddata);
856*4882a593Smuzhiyun 	if (error)
857*4882a593Smuzhiyun 		return error;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	atomic_set(&ddata->active, 1);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	psy_cfg.of_node = pdev->dev.of_node;
862*4882a593Smuzhiyun 	psy_cfg.drv_data = ddata;
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	ddata->usb = devm_power_supply_register(ddata->dev,
865*4882a593Smuzhiyun 						&cpcap_charger_usb_desc,
866*4882a593Smuzhiyun 						&psy_cfg);
867*4882a593Smuzhiyun 	if (IS_ERR(ddata->usb)) {
868*4882a593Smuzhiyun 		error = PTR_ERR(ddata->usb);
869*4882a593Smuzhiyun 		dev_err(ddata->dev, "failed to register USB charger: %i\n",
870*4882a593Smuzhiyun 			error);
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 		return error;
873*4882a593Smuzhiyun 	}
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	error = cpcap_usb_init_interrupts(pdev, ddata);
876*4882a593Smuzhiyun 	if (error)
877*4882a593Smuzhiyun 		return error;
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	ddata->comparator.set_vbus = cpcap_charger_set_vbus;
880*4882a593Smuzhiyun 	error = omap_usb2_set_comparator(&ddata->comparator);
881*4882a593Smuzhiyun 	if (error == -ENODEV) {
882*4882a593Smuzhiyun 		dev_info(ddata->dev, "charger needs phy, deferring probe\n");
883*4882a593Smuzhiyun 		return -EPROBE_DEFER;
884*4882a593Smuzhiyun 	}
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	cpcap_charger_init_optional_gpios(ddata);
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	schedule_delayed_work(&ddata->detect_work, 0);
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	return 0;
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun 
cpcap_charger_remove(struct platform_device * pdev)893*4882a593Smuzhiyun static int cpcap_charger_remove(struct platform_device *pdev)
894*4882a593Smuzhiyun {
895*4882a593Smuzhiyun 	struct cpcap_charger_ddata *ddata = platform_get_drvdata(pdev);
896*4882a593Smuzhiyun 	int error;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	atomic_set(&ddata->active, 0);
899*4882a593Smuzhiyun 	error = omap_usb2_set_comparator(NULL);
900*4882a593Smuzhiyun 	if (error)
901*4882a593Smuzhiyun 		dev_warn(ddata->dev, "could not clear USB comparator: %i\n",
902*4882a593Smuzhiyun 			 error);
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	error = cpcap_charger_set_state(ddata, 0, 0, 0);
905*4882a593Smuzhiyun 	if (error)
906*4882a593Smuzhiyun 		dev_warn(ddata->dev, "could not clear charger: %i\n",
907*4882a593Smuzhiyun 			 error);
908*4882a593Smuzhiyun 	cancel_delayed_work_sync(&ddata->vbus_work);
909*4882a593Smuzhiyun 	cancel_delayed_work_sync(&ddata->detect_work);
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	return 0;
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun static struct platform_driver cpcap_charger_driver = {
915*4882a593Smuzhiyun 	.probe = cpcap_charger_probe,
916*4882a593Smuzhiyun 	.driver	= {
917*4882a593Smuzhiyun 		.name	= "cpcap-charger",
918*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(cpcap_charger_id_table),
919*4882a593Smuzhiyun 	},
920*4882a593Smuzhiyun 	.remove	= cpcap_charger_remove,
921*4882a593Smuzhiyun };
922*4882a593Smuzhiyun module_platform_driver(cpcap_charger_driver);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
925*4882a593Smuzhiyun MODULE_DESCRIPTION("CPCAP Battery Charger Interface driver");
926*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
927*4882a593Smuzhiyun MODULE_ALIAS("platform:cpcap-charger");
928