xref: /OK3568_Linux_fs/kernel/drivers/power/supply/axp20x_usb_power.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * AXP20x PMIC USB power supply status driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
6*4882a593Smuzhiyun  * Copyright (C) 2014 Bruno Prémont <bonbons@linux-vserver.org>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/bitops.h>
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/mfd/axp20x.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/of_device.h>
18*4882a593Smuzhiyun #include <linux/platform_device.h>
19*4882a593Smuzhiyun #include <linux/pm.h>
20*4882a593Smuzhiyun #include <linux/power_supply.h>
21*4882a593Smuzhiyun #include <linux/regmap.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <linux/iio/consumer.h>
24*4882a593Smuzhiyun #include <linux/workqueue.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define DRVNAME "axp20x-usb-power-supply"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define AXP20X_PWR_STATUS_VBUS_PRESENT	BIT(5)
29*4882a593Smuzhiyun #define AXP20X_PWR_STATUS_VBUS_USED	BIT(4)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define AXP20X_USB_STATUS_VBUS_VALID	BIT(2)
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define AXP20X_VBUS_PATH_SEL		BIT(7)
34*4882a593Smuzhiyun #define AXP20X_VBUS_PATH_SEL_OFFSET	7
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define AXP20X_VBUS_VHOLD_uV(b)		(4000000 + (((b) >> 3) & 7) * 100000)
37*4882a593Smuzhiyun #define AXP20X_VBUS_VHOLD_MASK		GENMASK(5, 3)
38*4882a593Smuzhiyun #define AXP20X_VBUS_VHOLD_OFFSET	3
39*4882a593Smuzhiyun #define AXP20X_VBUS_CLIMIT_MASK		3
40*4882a593Smuzhiyun #define AXP20X_VBUS_CLIMIT_900mA	0
41*4882a593Smuzhiyun #define AXP20X_VBUS_CLIMIT_500mA	1
42*4882a593Smuzhiyun #define AXP20X_VBUS_CLIMIT_100mA	2
43*4882a593Smuzhiyun #define AXP20X_VBUS_CLIMIT_NONE		3
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define AXP813_VBUS_CLIMIT_900mA	0
46*4882a593Smuzhiyun #define AXP813_VBUS_CLIMIT_1500mA	1
47*4882a593Smuzhiyun #define AXP813_VBUS_CLIMIT_2000mA	2
48*4882a593Smuzhiyun #define AXP813_VBUS_CLIMIT_2500mA	3
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define AXP20X_ADC_EN1_VBUS_CURR	BIT(2)
51*4882a593Smuzhiyun #define AXP20X_ADC_EN1_VBUS_VOLT	BIT(3)
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define AXP20X_VBUS_MON_VBUS_VALID	BIT(3)
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define AXP813_BC_EN		BIT(0)
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /*
58*4882a593Smuzhiyun  * Note do not raise the debounce time, we must report Vusb high within
59*4882a593Smuzhiyun  * 100ms otherwise we get Vbus errors in musb.
60*4882a593Smuzhiyun  */
61*4882a593Smuzhiyun #define DEBOUNCE_TIME			msecs_to_jiffies(50)
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun struct axp20x_usb_power {
64*4882a593Smuzhiyun 	struct regmap *regmap;
65*4882a593Smuzhiyun 	struct power_supply *supply;
66*4882a593Smuzhiyun 	enum axp20x_variants axp20x_id;
67*4882a593Smuzhiyun 	struct iio_channel *vbus_v;
68*4882a593Smuzhiyun 	struct iio_channel *vbus_i;
69*4882a593Smuzhiyun 	struct delayed_work vbus_detect;
70*4882a593Smuzhiyun 	unsigned int old_status;
71*4882a593Smuzhiyun 	unsigned int online;
72*4882a593Smuzhiyun 	unsigned int num_irqs;
73*4882a593Smuzhiyun 	unsigned int irqs[];
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun 
axp20x_usb_vbus_needs_polling(struct axp20x_usb_power * power)76*4882a593Smuzhiyun static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	/*
79*4882a593Smuzhiyun 	 * Polling is only necessary while VBUS is offline. While online, a
80*4882a593Smuzhiyun 	 * present->absent transition implies an online->offline transition
81*4882a593Smuzhiyun 	 * and will trigger the VBUS_REMOVAL IRQ.
82*4882a593Smuzhiyun 	 */
83*4882a593Smuzhiyun 	if (power->axp20x_id >= AXP221_ID && !power->online)
84*4882a593Smuzhiyun 		return true;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	return false;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
axp20x_usb_power_irq(int irq,void * devid)89*4882a593Smuzhiyun static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct axp20x_usb_power *power = devid;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	power_supply_changed(power->supply);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return IRQ_HANDLED;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
axp20x_usb_power_poll_vbus(struct work_struct * work)100*4882a593Smuzhiyun static void axp20x_usb_power_poll_vbus(struct work_struct *work)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	struct axp20x_usb_power *power =
103*4882a593Smuzhiyun 		container_of(work, struct axp20x_usb_power, vbus_detect.work);
104*4882a593Smuzhiyun 	unsigned int val;
105*4882a593Smuzhiyun 	int ret;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);
108*4882a593Smuzhiyun 	if (ret)
109*4882a593Smuzhiyun 		goto out;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);
112*4882a593Smuzhiyun 	if (val != power->old_status)
113*4882a593Smuzhiyun 		power_supply_changed(power->supply);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	power->old_status = val;
116*4882a593Smuzhiyun 	power->online = val & AXP20X_PWR_STATUS_VBUS_USED;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun out:
119*4882a593Smuzhiyun 	if (axp20x_usb_vbus_needs_polling(power))
120*4882a593Smuzhiyun 		mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
axp20x_get_current_max(struct axp20x_usb_power * power,int * val)123*4882a593Smuzhiyun static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	unsigned int v;
126*4882a593Smuzhiyun 	int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	if (ret)
129*4882a593Smuzhiyun 		return ret;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	switch (v & AXP20X_VBUS_CLIMIT_MASK) {
132*4882a593Smuzhiyun 	case AXP20X_VBUS_CLIMIT_100mA:
133*4882a593Smuzhiyun 		if (power->axp20x_id == AXP221_ID)
134*4882a593Smuzhiyun 			*val = -1; /* No 100mA limit */
135*4882a593Smuzhiyun 		else
136*4882a593Smuzhiyun 			*val = 100000;
137*4882a593Smuzhiyun 		break;
138*4882a593Smuzhiyun 	case AXP20X_VBUS_CLIMIT_500mA:
139*4882a593Smuzhiyun 		*val = 500000;
140*4882a593Smuzhiyun 		break;
141*4882a593Smuzhiyun 	case AXP20X_VBUS_CLIMIT_900mA:
142*4882a593Smuzhiyun 		*val = 900000;
143*4882a593Smuzhiyun 		break;
144*4882a593Smuzhiyun 	case AXP20X_VBUS_CLIMIT_NONE:
145*4882a593Smuzhiyun 		*val = -1;
146*4882a593Smuzhiyun 		break;
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
axp813_get_current_max(struct axp20x_usb_power * power,int * val)152*4882a593Smuzhiyun static int axp813_get_current_max(struct axp20x_usb_power *power, int *val)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	unsigned int v;
155*4882a593Smuzhiyun 	int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (ret)
158*4882a593Smuzhiyun 		return ret;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	switch (v & AXP20X_VBUS_CLIMIT_MASK) {
161*4882a593Smuzhiyun 	case AXP813_VBUS_CLIMIT_900mA:
162*4882a593Smuzhiyun 		*val = 900000;
163*4882a593Smuzhiyun 		break;
164*4882a593Smuzhiyun 	case AXP813_VBUS_CLIMIT_1500mA:
165*4882a593Smuzhiyun 		*val = 1500000;
166*4882a593Smuzhiyun 		break;
167*4882a593Smuzhiyun 	case AXP813_VBUS_CLIMIT_2000mA:
168*4882a593Smuzhiyun 		*val = 2000000;
169*4882a593Smuzhiyun 		break;
170*4882a593Smuzhiyun 	case AXP813_VBUS_CLIMIT_2500mA:
171*4882a593Smuzhiyun 		*val = 2500000;
172*4882a593Smuzhiyun 		break;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 	return 0;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
axp20x_usb_power_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)177*4882a593Smuzhiyun static int axp20x_usb_power_get_property(struct power_supply *psy,
178*4882a593Smuzhiyun 	enum power_supply_property psp, union power_supply_propval *val)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
181*4882a593Smuzhiyun 	unsigned int input, v;
182*4882a593Smuzhiyun 	int ret;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	switch (psp) {
185*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
186*4882a593Smuzhiyun 		ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
187*4882a593Smuzhiyun 		if (ret)
188*4882a593Smuzhiyun 			return ret;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 		val->intval = AXP20X_VBUS_VHOLD_uV(v);
191*4882a593Smuzhiyun 		return 0;
192*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
193*4882a593Smuzhiyun 		if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
194*4882a593Smuzhiyun 			ret = iio_read_channel_processed(power->vbus_v,
195*4882a593Smuzhiyun 							 &val->intval);
196*4882a593Smuzhiyun 			if (ret)
197*4882a593Smuzhiyun 				return ret;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 			/*
200*4882a593Smuzhiyun 			 * IIO framework gives mV but Power Supply framework
201*4882a593Smuzhiyun 			 * gives uV.
202*4882a593Smuzhiyun 			 */
203*4882a593Smuzhiyun 			val->intval *= 1000;
204*4882a593Smuzhiyun 			return 0;
205*4882a593Smuzhiyun 		}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		ret = axp20x_read_variable_width(power->regmap,
208*4882a593Smuzhiyun 						 AXP20X_VBUS_V_ADC_H, 12);
209*4882a593Smuzhiyun 		if (ret < 0)
210*4882a593Smuzhiyun 			return ret;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 		val->intval = ret * 1700; /* 1 step = 1.7 mV */
213*4882a593Smuzhiyun 		return 0;
214*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_MAX:
215*4882a593Smuzhiyun 		if (power->axp20x_id == AXP813_ID)
216*4882a593Smuzhiyun 			return axp813_get_current_max(power, &val->intval);
217*4882a593Smuzhiyun 		return axp20x_get_current_max(power, &val->intval);
218*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_NOW:
219*4882a593Smuzhiyun 		if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
220*4882a593Smuzhiyun 			ret = iio_read_channel_processed(power->vbus_i,
221*4882a593Smuzhiyun 							 &val->intval);
222*4882a593Smuzhiyun 			if (ret)
223*4882a593Smuzhiyun 				return ret;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 			/*
226*4882a593Smuzhiyun 			 * IIO framework gives mA but Power Supply framework
227*4882a593Smuzhiyun 			 * gives uA.
228*4882a593Smuzhiyun 			 */
229*4882a593Smuzhiyun 			val->intval *= 1000;
230*4882a593Smuzhiyun 			return 0;
231*4882a593Smuzhiyun 		}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		ret = axp20x_read_variable_width(power->regmap,
234*4882a593Smuzhiyun 						 AXP20X_VBUS_I_ADC_H, 12);
235*4882a593Smuzhiyun 		if (ret < 0)
236*4882a593Smuzhiyun 			return ret;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 		val->intval = ret * 375; /* 1 step = 0.375 mA */
239*4882a593Smuzhiyun 		return 0;
240*4882a593Smuzhiyun 	default:
241*4882a593Smuzhiyun 		break;
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	/* All the properties below need the input-status reg value */
245*4882a593Smuzhiyun 	ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &input);
246*4882a593Smuzhiyun 	if (ret)
247*4882a593Smuzhiyun 		return ret;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	switch (psp) {
250*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_HEALTH:
251*4882a593Smuzhiyun 		if (!(input & AXP20X_PWR_STATUS_VBUS_PRESENT)) {
252*4882a593Smuzhiyun 			val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
253*4882a593Smuzhiyun 			break;
254*4882a593Smuzhiyun 		}
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 		val->intval = POWER_SUPPLY_HEALTH_GOOD;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 		if (power->axp20x_id == AXP202_ID) {
259*4882a593Smuzhiyun 			ret = regmap_read(power->regmap,
260*4882a593Smuzhiyun 					  AXP20X_USB_OTG_STATUS, &v);
261*4882a593Smuzhiyun 			if (ret)
262*4882a593Smuzhiyun 				return ret;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 			if (!(v & AXP20X_USB_STATUS_VBUS_VALID))
265*4882a593Smuzhiyun 				val->intval =
266*4882a593Smuzhiyun 					POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
267*4882a593Smuzhiyun 		}
268*4882a593Smuzhiyun 		break;
269*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_PRESENT:
270*4882a593Smuzhiyun 		val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT);
271*4882a593Smuzhiyun 		break;
272*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ONLINE:
273*4882a593Smuzhiyun 		val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_USED);
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	default:
276*4882a593Smuzhiyun 		return -EINVAL;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	return 0;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
axp813_usb_power_set_online(struct axp20x_usb_power * power,int intval)282*4882a593Smuzhiyun static int axp813_usb_power_set_online(struct axp20x_usb_power *power,
283*4882a593Smuzhiyun 				       int intval)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	int val = !intval << AXP20X_VBUS_PATH_SEL_OFFSET;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	return regmap_update_bits(power->regmap,
288*4882a593Smuzhiyun 				  AXP20X_VBUS_IPSOUT_MGMT,
289*4882a593Smuzhiyun 				  AXP20X_VBUS_PATH_SEL, val);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
axp20x_usb_power_set_voltage_min(struct axp20x_usb_power * power,int intval)292*4882a593Smuzhiyun static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power,
293*4882a593Smuzhiyun 					    int intval)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	int val;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	switch (intval) {
298*4882a593Smuzhiyun 	case 4000000:
299*4882a593Smuzhiyun 	case 4100000:
300*4882a593Smuzhiyun 	case 4200000:
301*4882a593Smuzhiyun 	case 4300000:
302*4882a593Smuzhiyun 	case 4400000:
303*4882a593Smuzhiyun 	case 4500000:
304*4882a593Smuzhiyun 	case 4600000:
305*4882a593Smuzhiyun 	case 4700000:
306*4882a593Smuzhiyun 		val = (intval - 4000000) / 100000;
307*4882a593Smuzhiyun 		return regmap_update_bits(power->regmap,
308*4882a593Smuzhiyun 					  AXP20X_VBUS_IPSOUT_MGMT,
309*4882a593Smuzhiyun 					  AXP20X_VBUS_VHOLD_MASK,
310*4882a593Smuzhiyun 					  val << AXP20X_VBUS_VHOLD_OFFSET);
311*4882a593Smuzhiyun 	default:
312*4882a593Smuzhiyun 		return -EINVAL;
313*4882a593Smuzhiyun 	}
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return -EINVAL;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
axp813_usb_power_set_current_max(struct axp20x_usb_power * power,int intval)318*4882a593Smuzhiyun static int axp813_usb_power_set_current_max(struct axp20x_usb_power *power,
319*4882a593Smuzhiyun 					    int intval)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	int val;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	switch (intval) {
324*4882a593Smuzhiyun 	case 900000:
325*4882a593Smuzhiyun 		return regmap_update_bits(power->regmap,
326*4882a593Smuzhiyun 					  AXP20X_VBUS_IPSOUT_MGMT,
327*4882a593Smuzhiyun 					  AXP20X_VBUS_CLIMIT_MASK,
328*4882a593Smuzhiyun 					  AXP813_VBUS_CLIMIT_900mA);
329*4882a593Smuzhiyun 	case 1500000:
330*4882a593Smuzhiyun 	case 2000000:
331*4882a593Smuzhiyun 	case 2500000:
332*4882a593Smuzhiyun 		val = (intval - 1000000) / 500000;
333*4882a593Smuzhiyun 		return regmap_update_bits(power->regmap,
334*4882a593Smuzhiyun 					  AXP20X_VBUS_IPSOUT_MGMT,
335*4882a593Smuzhiyun 					  AXP20X_VBUS_CLIMIT_MASK, val);
336*4882a593Smuzhiyun 	default:
337*4882a593Smuzhiyun 		return -EINVAL;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	return -EINVAL;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
axp20x_usb_power_set_current_max(struct axp20x_usb_power * power,int intval)343*4882a593Smuzhiyun static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power,
344*4882a593Smuzhiyun 					    int intval)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	int val;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	switch (intval) {
349*4882a593Smuzhiyun 	case 100000:
350*4882a593Smuzhiyun 		if (power->axp20x_id == AXP221_ID)
351*4882a593Smuzhiyun 			return -EINVAL;
352*4882a593Smuzhiyun 		fallthrough;
353*4882a593Smuzhiyun 	case 500000:
354*4882a593Smuzhiyun 	case 900000:
355*4882a593Smuzhiyun 		val = (900000 - intval) / 400000;
356*4882a593Smuzhiyun 		return regmap_update_bits(power->regmap,
357*4882a593Smuzhiyun 					  AXP20X_VBUS_IPSOUT_MGMT,
358*4882a593Smuzhiyun 					  AXP20X_VBUS_CLIMIT_MASK, val);
359*4882a593Smuzhiyun 	default:
360*4882a593Smuzhiyun 		return -EINVAL;
361*4882a593Smuzhiyun 	}
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	return -EINVAL;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
axp20x_usb_power_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)366*4882a593Smuzhiyun static int axp20x_usb_power_set_property(struct power_supply *psy,
367*4882a593Smuzhiyun 					 enum power_supply_property psp,
368*4882a593Smuzhiyun 					 const union power_supply_propval *val)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	switch (psp) {
373*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ONLINE:
374*4882a593Smuzhiyun 		if (power->axp20x_id != AXP813_ID)
375*4882a593Smuzhiyun 			return -EINVAL;
376*4882a593Smuzhiyun 		return axp813_usb_power_set_online(power, val->intval);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
379*4882a593Smuzhiyun 		return axp20x_usb_power_set_voltage_min(power, val->intval);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_MAX:
382*4882a593Smuzhiyun 		if (power->axp20x_id == AXP813_ID)
383*4882a593Smuzhiyun 			return axp813_usb_power_set_current_max(power,
384*4882a593Smuzhiyun 								val->intval);
385*4882a593Smuzhiyun 		return axp20x_usb_power_set_current_max(power, val->intval);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	default:
388*4882a593Smuzhiyun 		return -EINVAL;
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	return -EINVAL;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
axp20x_usb_power_prop_writeable(struct power_supply * psy,enum power_supply_property psp)394*4882a593Smuzhiyun static int axp20x_usb_power_prop_writeable(struct power_supply *psy,
395*4882a593Smuzhiyun 					   enum power_supply_property psp)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun 	struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/*
400*4882a593Smuzhiyun 	 * The VBUS path select flag works differently on on AXP288 and newer:
401*4882a593Smuzhiyun 	 *  - On AXP20x and AXP22x, the flag enables VBUS (ignoring N_VBUSEN).
402*4882a593Smuzhiyun 	 *  - On AXP288 and AXP8xx, the flag disables VBUS (ignoring N_VBUSEN).
403*4882a593Smuzhiyun 	 * We only expose the control on variants where it can be used to force
404*4882a593Smuzhiyun 	 * the VBUS input offline.
405*4882a593Smuzhiyun 	 */
406*4882a593Smuzhiyun 	if (psp == POWER_SUPPLY_PROP_ONLINE)
407*4882a593Smuzhiyun 		return power->axp20x_id == AXP813_ID;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
410*4882a593Smuzhiyun 	       psp == POWER_SUPPLY_PROP_CURRENT_MAX;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun static enum power_supply_property axp20x_usb_power_properties[] = {
414*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_HEALTH,
415*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_PRESENT,
416*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ONLINE,
417*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_MIN,
418*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
419*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_MAX,
420*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_NOW,
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun static enum power_supply_property axp22x_usb_power_properties[] = {
424*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_HEALTH,
425*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_PRESENT,
426*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ONLINE,
427*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_MIN,
428*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_MAX,
429*4882a593Smuzhiyun };
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun static const struct power_supply_desc axp20x_usb_power_desc = {
432*4882a593Smuzhiyun 	.name = "axp20x-usb",
433*4882a593Smuzhiyun 	.type = POWER_SUPPLY_TYPE_USB,
434*4882a593Smuzhiyun 	.properties = axp20x_usb_power_properties,
435*4882a593Smuzhiyun 	.num_properties = ARRAY_SIZE(axp20x_usb_power_properties),
436*4882a593Smuzhiyun 	.property_is_writeable = axp20x_usb_power_prop_writeable,
437*4882a593Smuzhiyun 	.get_property = axp20x_usb_power_get_property,
438*4882a593Smuzhiyun 	.set_property = axp20x_usb_power_set_property,
439*4882a593Smuzhiyun };
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun static const struct power_supply_desc axp22x_usb_power_desc = {
442*4882a593Smuzhiyun 	.name = "axp20x-usb",
443*4882a593Smuzhiyun 	.type = POWER_SUPPLY_TYPE_USB,
444*4882a593Smuzhiyun 	.properties = axp22x_usb_power_properties,
445*4882a593Smuzhiyun 	.num_properties = ARRAY_SIZE(axp22x_usb_power_properties),
446*4882a593Smuzhiyun 	.property_is_writeable = axp20x_usb_power_prop_writeable,
447*4882a593Smuzhiyun 	.get_property = axp20x_usb_power_get_property,
448*4882a593Smuzhiyun 	.set_property = axp20x_usb_power_set_property,
449*4882a593Smuzhiyun };
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun static const char * const axp20x_irq_names[] = {
452*4882a593Smuzhiyun 	"VBUS_PLUGIN",
453*4882a593Smuzhiyun 	"VBUS_REMOVAL",
454*4882a593Smuzhiyun 	"VBUS_VALID",
455*4882a593Smuzhiyun 	"VBUS_NOT_VALID",
456*4882a593Smuzhiyun };
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun static const char * const axp22x_irq_names[] = {
459*4882a593Smuzhiyun 	"VBUS_PLUGIN",
460*4882a593Smuzhiyun 	"VBUS_REMOVAL",
461*4882a593Smuzhiyun };
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun struct axp_data {
464*4882a593Smuzhiyun 	const struct power_supply_desc	*power_desc;
465*4882a593Smuzhiyun 	const char * const		*irq_names;
466*4882a593Smuzhiyun 	unsigned int			num_irq_names;
467*4882a593Smuzhiyun 	enum axp20x_variants		axp20x_id;
468*4882a593Smuzhiyun };
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun static const struct axp_data axp202_data = {
471*4882a593Smuzhiyun 	.power_desc	= &axp20x_usb_power_desc,
472*4882a593Smuzhiyun 	.irq_names	= axp20x_irq_names,
473*4882a593Smuzhiyun 	.num_irq_names	= ARRAY_SIZE(axp20x_irq_names),
474*4882a593Smuzhiyun 	.axp20x_id	= AXP202_ID,
475*4882a593Smuzhiyun };
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun static const struct axp_data axp221_data = {
478*4882a593Smuzhiyun 	.power_desc	= &axp22x_usb_power_desc,
479*4882a593Smuzhiyun 	.irq_names	= axp22x_irq_names,
480*4882a593Smuzhiyun 	.num_irq_names	= ARRAY_SIZE(axp22x_irq_names),
481*4882a593Smuzhiyun 	.axp20x_id	= AXP221_ID,
482*4882a593Smuzhiyun };
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun static const struct axp_data axp223_data = {
485*4882a593Smuzhiyun 	.power_desc	= &axp22x_usb_power_desc,
486*4882a593Smuzhiyun 	.irq_names	= axp22x_irq_names,
487*4882a593Smuzhiyun 	.num_irq_names	= ARRAY_SIZE(axp22x_irq_names),
488*4882a593Smuzhiyun 	.axp20x_id	= AXP223_ID,
489*4882a593Smuzhiyun };
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun static const struct axp_data axp813_data = {
492*4882a593Smuzhiyun 	.power_desc	= &axp22x_usb_power_desc,
493*4882a593Smuzhiyun 	.irq_names	= axp22x_irq_names,
494*4882a593Smuzhiyun 	.num_irq_names	= ARRAY_SIZE(axp22x_irq_names),
495*4882a593Smuzhiyun 	.axp20x_id	= AXP813_ID,
496*4882a593Smuzhiyun };
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
axp20x_usb_power_suspend(struct device * dev)499*4882a593Smuzhiyun static int axp20x_usb_power_suspend(struct device *dev)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	struct axp20x_usb_power *power = dev_get_drvdata(dev);
502*4882a593Smuzhiyun 	int i = 0;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	/*
505*4882a593Smuzhiyun 	 * Allow wake via VBUS_PLUGIN only.
506*4882a593Smuzhiyun 	 *
507*4882a593Smuzhiyun 	 * As nested threaded IRQs are not automatically disabled during
508*4882a593Smuzhiyun 	 * suspend, we must explicitly disable the remainder of the IRQs.
509*4882a593Smuzhiyun 	 */
510*4882a593Smuzhiyun 	if (device_may_wakeup(&power->supply->dev))
511*4882a593Smuzhiyun 		enable_irq_wake(power->irqs[i++]);
512*4882a593Smuzhiyun 	while (i < power->num_irqs)
513*4882a593Smuzhiyun 		disable_irq(power->irqs[i++]);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	return 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
axp20x_usb_power_resume(struct device * dev)518*4882a593Smuzhiyun static int axp20x_usb_power_resume(struct device *dev)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct axp20x_usb_power *power = dev_get_drvdata(dev);
521*4882a593Smuzhiyun 	int i = 0;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	if (device_may_wakeup(&power->supply->dev))
524*4882a593Smuzhiyun 		disable_irq_wake(power->irqs[i++]);
525*4882a593Smuzhiyun 	while (i < power->num_irqs)
526*4882a593Smuzhiyun 		enable_irq(power->irqs[i++]);
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun #endif
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(axp20x_usb_power_pm_ops, axp20x_usb_power_suspend,
535*4882a593Smuzhiyun 						  axp20x_usb_power_resume);
536*4882a593Smuzhiyun 
configure_iio_channels(struct platform_device * pdev,struct axp20x_usb_power * power)537*4882a593Smuzhiyun static int configure_iio_channels(struct platform_device *pdev,
538*4882a593Smuzhiyun 				  struct axp20x_usb_power *power)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
541*4882a593Smuzhiyun 	if (IS_ERR(power->vbus_v)) {
542*4882a593Smuzhiyun 		if (PTR_ERR(power->vbus_v) == -ENODEV)
543*4882a593Smuzhiyun 			return -EPROBE_DEFER;
544*4882a593Smuzhiyun 		return PTR_ERR(power->vbus_v);
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i");
548*4882a593Smuzhiyun 	if (IS_ERR(power->vbus_i)) {
549*4882a593Smuzhiyun 		if (PTR_ERR(power->vbus_i) == -ENODEV)
550*4882a593Smuzhiyun 			return -EPROBE_DEFER;
551*4882a593Smuzhiyun 		return PTR_ERR(power->vbus_i);
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	return 0;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
configure_adc_registers(struct axp20x_usb_power * power)557*4882a593Smuzhiyun static int configure_adc_registers(struct axp20x_usb_power *power)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	/* Enable vbus voltage and current measurement */
560*4882a593Smuzhiyun 	return regmap_update_bits(power->regmap, AXP20X_ADC_EN1,
561*4882a593Smuzhiyun 				  AXP20X_ADC_EN1_VBUS_CURR |
562*4882a593Smuzhiyun 				  AXP20X_ADC_EN1_VBUS_VOLT,
563*4882a593Smuzhiyun 				  AXP20X_ADC_EN1_VBUS_CURR |
564*4882a593Smuzhiyun 				  AXP20X_ADC_EN1_VBUS_VOLT);
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun 
axp20x_usb_power_probe(struct platform_device * pdev)567*4882a593Smuzhiyun static int axp20x_usb_power_probe(struct platform_device *pdev)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
570*4882a593Smuzhiyun 	struct power_supply_config psy_cfg = {};
571*4882a593Smuzhiyun 	struct axp20x_usb_power *power;
572*4882a593Smuzhiyun 	const struct axp_data *axp_data;
573*4882a593Smuzhiyun 	int i, irq, ret;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	if (!of_device_is_available(pdev->dev.of_node))
576*4882a593Smuzhiyun 		return -ENODEV;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	if (!axp20x) {
579*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Parent drvdata not set\n");
580*4882a593Smuzhiyun 		return -EINVAL;
581*4882a593Smuzhiyun 	}
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	axp_data = of_device_get_match_data(&pdev->dev);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	power = devm_kzalloc(&pdev->dev,
586*4882a593Smuzhiyun 			     struct_size(power, irqs, axp_data->num_irq_names),
587*4882a593Smuzhiyun 			     GFP_KERNEL);
588*4882a593Smuzhiyun 	if (!power)
589*4882a593Smuzhiyun 		return -ENOMEM;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	platform_set_drvdata(pdev, power);
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	power->axp20x_id = axp_data->axp20x_id;
594*4882a593Smuzhiyun 	power->regmap = axp20x->regmap;
595*4882a593Smuzhiyun 	power->num_irqs = axp_data->num_irq_names;
596*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (power->axp20x_id == AXP202_ID) {
599*4882a593Smuzhiyun 		/* Enable vbus valid checking */
600*4882a593Smuzhiyun 		ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON,
601*4882a593Smuzhiyun 					 AXP20X_VBUS_MON_VBUS_VALID,
602*4882a593Smuzhiyun 					 AXP20X_VBUS_MON_VBUS_VALID);
603*4882a593Smuzhiyun 		if (ret)
604*4882a593Smuzhiyun 			return ret;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 		if (IS_ENABLED(CONFIG_AXP20X_ADC))
607*4882a593Smuzhiyun 			ret = configure_iio_channels(pdev, power);
608*4882a593Smuzhiyun 		else
609*4882a593Smuzhiyun 			ret = configure_adc_registers(power);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 		if (ret)
612*4882a593Smuzhiyun 			return ret;
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	if (power->axp20x_id == AXP813_ID) {
616*4882a593Smuzhiyun 		/* Enable USB Battery Charging specification detection */
617*4882a593Smuzhiyun 		regmap_update_bits(axp20x->regmap, AXP288_BC_GLOBAL,
618*4882a593Smuzhiyun 				   AXP813_BC_EN, AXP813_BC_EN);
619*4882a593Smuzhiyun 	}
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	psy_cfg.of_node = pdev->dev.of_node;
622*4882a593Smuzhiyun 	psy_cfg.drv_data = power;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	power->supply = devm_power_supply_register(&pdev->dev,
625*4882a593Smuzhiyun 						   axp_data->power_desc,
626*4882a593Smuzhiyun 						   &psy_cfg);
627*4882a593Smuzhiyun 	if (IS_ERR(power->supply))
628*4882a593Smuzhiyun 		return PTR_ERR(power->supply);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	/* Request irqs after registering, as irqs may trigger immediately */
631*4882a593Smuzhiyun 	for (i = 0; i < axp_data->num_irq_names; i++) {
632*4882a593Smuzhiyun 		irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]);
633*4882a593Smuzhiyun 		if (irq < 0) {
634*4882a593Smuzhiyun 			dev_err(&pdev->dev, "No IRQ for %s: %d\n",
635*4882a593Smuzhiyun 				axp_data->irq_names[i], irq);
636*4882a593Smuzhiyun 			return irq;
637*4882a593Smuzhiyun 		}
638*4882a593Smuzhiyun 		power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
639*4882a593Smuzhiyun 		ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i],
640*4882a593Smuzhiyun 						   axp20x_usb_power_irq, 0,
641*4882a593Smuzhiyun 						   DRVNAME, power);
642*4882a593Smuzhiyun 		if (ret < 0) {
643*4882a593Smuzhiyun 			dev_err(&pdev->dev, "Error requesting %s IRQ: %d\n",
644*4882a593Smuzhiyun 				axp_data->irq_names[i], ret);
645*4882a593Smuzhiyun 			return ret;
646*4882a593Smuzhiyun 		}
647*4882a593Smuzhiyun 	}
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	if (axp20x_usb_vbus_needs_polling(power))
650*4882a593Smuzhiyun 		queue_delayed_work(system_wq, &power->vbus_detect, 0);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	return 0;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun 
axp20x_usb_power_remove(struct platform_device * pdev)655*4882a593Smuzhiyun static int axp20x_usb_power_remove(struct platform_device *pdev)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun 	struct axp20x_usb_power *power = platform_get_drvdata(pdev);
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	cancel_delayed_work_sync(&power->vbus_detect);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun static const struct of_device_id axp20x_usb_power_match[] = {
665*4882a593Smuzhiyun 	{
666*4882a593Smuzhiyun 		.compatible = "x-powers,axp202-usb-power-supply",
667*4882a593Smuzhiyun 		.data = &axp202_data,
668*4882a593Smuzhiyun 	}, {
669*4882a593Smuzhiyun 		.compatible = "x-powers,axp221-usb-power-supply",
670*4882a593Smuzhiyun 		.data = &axp221_data,
671*4882a593Smuzhiyun 	}, {
672*4882a593Smuzhiyun 		.compatible = "x-powers,axp223-usb-power-supply",
673*4882a593Smuzhiyun 		.data = &axp223_data,
674*4882a593Smuzhiyun 	}, {
675*4882a593Smuzhiyun 		.compatible = "x-powers,axp813-usb-power-supply",
676*4882a593Smuzhiyun 		.data = &axp813_data,
677*4882a593Smuzhiyun 	}, { /* sentinel */ }
678*4882a593Smuzhiyun };
679*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun static struct platform_driver axp20x_usb_power_driver = {
682*4882a593Smuzhiyun 	.probe = axp20x_usb_power_probe,
683*4882a593Smuzhiyun 	.remove = axp20x_usb_power_remove,
684*4882a593Smuzhiyun 	.driver = {
685*4882a593Smuzhiyun 		.name		= DRVNAME,
686*4882a593Smuzhiyun 		.of_match_table	= axp20x_usb_power_match,
687*4882a593Smuzhiyun 		.pm		= &axp20x_usb_power_pm_ops,
688*4882a593Smuzhiyun 	},
689*4882a593Smuzhiyun };
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun module_platform_driver(axp20x_usb_power_driver);
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
694*4882a593Smuzhiyun MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");
695*4882a593Smuzhiyun MODULE_LICENSE("GPL");
696