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