xref: /OK3568_Linux_fs/kernel/drivers/power/supply/max8903_charger.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2011 Samsung Electronics
6*4882a593Smuzhiyun  * MyungJoo Ham <myungjoo.ham@samsung.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/gpio.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/of.h>
13*4882a593Smuzhiyun #include <linux/of_device.h>
14*4882a593Smuzhiyun #include <linux/of_gpio.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/power_supply.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/power/max8903_charger.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun struct max8903_data {
21*4882a593Smuzhiyun 	struct max8903_pdata *pdata;
22*4882a593Smuzhiyun 	struct device *dev;
23*4882a593Smuzhiyun 	struct power_supply *psy;
24*4882a593Smuzhiyun 	struct power_supply_desc psy_desc;
25*4882a593Smuzhiyun 	bool fault;
26*4882a593Smuzhiyun 	bool usb_in;
27*4882a593Smuzhiyun 	bool ta_in;
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static enum power_supply_property max8903_charger_props[] = {
31*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_STATUS, /* Charger status output */
32*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ONLINE, /* External power source */
33*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_HEALTH, /* Fault or OK */
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun 
max8903_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)36*4882a593Smuzhiyun static int max8903_get_property(struct power_supply *psy,
37*4882a593Smuzhiyun 		enum power_supply_property psp,
38*4882a593Smuzhiyun 		union power_supply_propval *val)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	struct max8903_data *data = power_supply_get_drvdata(psy);
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	switch (psp) {
43*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
44*4882a593Smuzhiyun 		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
45*4882a593Smuzhiyun 		if (gpio_is_valid(data->pdata->chg)) {
46*4882a593Smuzhiyun 			if (gpio_get_value(data->pdata->chg) == 0)
47*4882a593Smuzhiyun 				val->intval = POWER_SUPPLY_STATUS_CHARGING;
48*4882a593Smuzhiyun 			else if (data->usb_in || data->ta_in)
49*4882a593Smuzhiyun 				val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
50*4882a593Smuzhiyun 			else
51*4882a593Smuzhiyun 				val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
52*4882a593Smuzhiyun 		}
53*4882a593Smuzhiyun 		break;
54*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ONLINE:
55*4882a593Smuzhiyun 		val->intval = 0;
56*4882a593Smuzhiyun 		if (data->usb_in || data->ta_in)
57*4882a593Smuzhiyun 			val->intval = 1;
58*4882a593Smuzhiyun 		break;
59*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_HEALTH:
60*4882a593Smuzhiyun 		val->intval = POWER_SUPPLY_HEALTH_GOOD;
61*4882a593Smuzhiyun 		if (data->fault)
62*4882a593Smuzhiyun 			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
63*4882a593Smuzhiyun 		break;
64*4882a593Smuzhiyun 	default:
65*4882a593Smuzhiyun 		return -EINVAL;
66*4882a593Smuzhiyun 	}
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	return 0;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
max8903_dcin(int irq,void * _data)71*4882a593Smuzhiyun static irqreturn_t max8903_dcin(int irq, void *_data)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct max8903_data *data = _data;
74*4882a593Smuzhiyun 	struct max8903_pdata *pdata = data->pdata;
75*4882a593Smuzhiyun 	bool ta_in;
76*4882a593Smuzhiyun 	enum power_supply_type old_type;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	ta_in = gpio_get_value(pdata->dok) ? false : true;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	if (ta_in == data->ta_in)
81*4882a593Smuzhiyun 		return IRQ_HANDLED;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	data->ta_in = ta_in;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	/* Set Current-Limit-Mode 1:DC 0:USB */
86*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->dcm))
87*4882a593Smuzhiyun 		gpio_set_value(pdata->dcm, ta_in ? 1 : 0);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	/* Charger Enable / Disable (cen is negated) */
90*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->cen))
91*4882a593Smuzhiyun 		gpio_set_value(pdata->cen, ta_in ? 0 :
92*4882a593Smuzhiyun 				(data->usb_in ? 0 : 1));
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	dev_dbg(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ?
95*4882a593Smuzhiyun 			"Connected" : "Disconnected");
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	old_type = data->psy_desc.type;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if (data->ta_in)
100*4882a593Smuzhiyun 		data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
101*4882a593Smuzhiyun 	else if (data->usb_in)
102*4882a593Smuzhiyun 		data->psy_desc.type = POWER_SUPPLY_TYPE_USB;
103*4882a593Smuzhiyun 	else
104*4882a593Smuzhiyun 		data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	if (old_type != data->psy_desc.type)
107*4882a593Smuzhiyun 		power_supply_changed(data->psy);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return IRQ_HANDLED;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
max8903_usbin(int irq,void * _data)112*4882a593Smuzhiyun static irqreturn_t max8903_usbin(int irq, void *_data)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	struct max8903_data *data = _data;
115*4882a593Smuzhiyun 	struct max8903_pdata *pdata = data->pdata;
116*4882a593Smuzhiyun 	bool usb_in;
117*4882a593Smuzhiyun 	enum power_supply_type old_type;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	usb_in = gpio_get_value(pdata->uok) ? false : true;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	if (usb_in == data->usb_in)
122*4882a593Smuzhiyun 		return IRQ_HANDLED;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	data->usb_in = usb_in;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	/* Do not touch Current-Limit-Mode */
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* Charger Enable / Disable (cen is negated) */
129*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->cen))
130*4882a593Smuzhiyun 		gpio_set_value(pdata->cen, usb_in ? 0 :
131*4882a593Smuzhiyun 				(data->ta_in ? 0 : 1));
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	dev_dbg(data->dev, "USB Charger %s.\n", usb_in ?
134*4882a593Smuzhiyun 			"Connected" : "Disconnected");
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	old_type = data->psy_desc.type;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if (data->ta_in)
139*4882a593Smuzhiyun 		data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
140*4882a593Smuzhiyun 	else if (data->usb_in)
141*4882a593Smuzhiyun 		data->psy_desc.type = POWER_SUPPLY_TYPE_USB;
142*4882a593Smuzhiyun 	else
143*4882a593Smuzhiyun 		data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	if (old_type != data->psy_desc.type)
146*4882a593Smuzhiyun 		power_supply_changed(data->psy);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return IRQ_HANDLED;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
max8903_fault(int irq,void * _data)151*4882a593Smuzhiyun static irqreturn_t max8903_fault(int irq, void *_data)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct max8903_data *data = _data;
154*4882a593Smuzhiyun 	struct max8903_pdata *pdata = data->pdata;
155*4882a593Smuzhiyun 	bool fault;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	fault = gpio_get_value(pdata->flt) ? false : true;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (fault == data->fault)
160*4882a593Smuzhiyun 		return IRQ_HANDLED;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	data->fault = fault;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (fault)
165*4882a593Smuzhiyun 		dev_err(data->dev, "Charger suffers a fault and stops.\n");
166*4882a593Smuzhiyun 	else
167*4882a593Smuzhiyun 		dev_err(data->dev, "Charger recovered from a fault.\n");
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return IRQ_HANDLED;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
max8903_parse_dt_data(struct device * dev)172*4882a593Smuzhiyun static struct max8903_pdata *max8903_parse_dt_data(struct device *dev)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
175*4882a593Smuzhiyun 	struct max8903_pdata *pdata = NULL;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (!np)
178*4882a593Smuzhiyun 		return NULL;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
181*4882a593Smuzhiyun 	if (!pdata)
182*4882a593Smuzhiyun 		return NULL;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	pdata->dc_valid = false;
185*4882a593Smuzhiyun 	pdata->usb_valid = false;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	pdata->cen = of_get_named_gpio(np, "cen-gpios", 0);
188*4882a593Smuzhiyun 	if (!gpio_is_valid(pdata->cen))
189*4882a593Smuzhiyun 		pdata->cen = -EINVAL;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	pdata->chg = of_get_named_gpio(np, "chg-gpios", 0);
192*4882a593Smuzhiyun 	if (!gpio_is_valid(pdata->chg))
193*4882a593Smuzhiyun 		pdata->chg = -EINVAL;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	pdata->flt = of_get_named_gpio(np, "flt-gpios", 0);
196*4882a593Smuzhiyun 	if (!gpio_is_valid(pdata->flt))
197*4882a593Smuzhiyun 		pdata->flt = -EINVAL;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	pdata->usus = of_get_named_gpio(np, "usus-gpios", 0);
200*4882a593Smuzhiyun 	if (!gpio_is_valid(pdata->usus))
201*4882a593Smuzhiyun 		pdata->usus = -EINVAL;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	pdata->dcm = of_get_named_gpio(np, "dcm-gpios", 0);
204*4882a593Smuzhiyun 	if (!gpio_is_valid(pdata->dcm))
205*4882a593Smuzhiyun 		pdata->dcm = -EINVAL;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	pdata->dok = of_get_named_gpio(np, "dok-gpios", 0);
208*4882a593Smuzhiyun 	if (!gpio_is_valid(pdata->dok))
209*4882a593Smuzhiyun 		pdata->dok = -EINVAL;
210*4882a593Smuzhiyun 	else
211*4882a593Smuzhiyun 		pdata->dc_valid = true;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	pdata->uok = of_get_named_gpio(np, "uok-gpios", 0);
214*4882a593Smuzhiyun 	if (!gpio_is_valid(pdata->uok))
215*4882a593Smuzhiyun 		pdata->uok = -EINVAL;
216*4882a593Smuzhiyun 	else
217*4882a593Smuzhiyun 		pdata->usb_valid = true;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return pdata;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
max8903_setup_gpios(struct platform_device * pdev)222*4882a593Smuzhiyun static int max8903_setup_gpios(struct platform_device *pdev)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct max8903_data *data = platform_get_drvdata(pdev);
225*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
226*4882a593Smuzhiyun 	struct max8903_pdata *pdata = pdev->dev.platform_data;
227*4882a593Smuzhiyun 	int ret = 0;
228*4882a593Smuzhiyun 	int gpio;
229*4882a593Smuzhiyun 	int ta_in = 0;
230*4882a593Smuzhiyun 	int usb_in = 0;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	if (pdata->dc_valid) {
233*4882a593Smuzhiyun 		if (gpio_is_valid(pdata->dok)) {
234*4882a593Smuzhiyun 			ret = devm_gpio_request(dev, pdata->dok,
235*4882a593Smuzhiyun 						data->psy_desc.name);
236*4882a593Smuzhiyun 			if (ret) {
237*4882a593Smuzhiyun 				dev_err(dev,
238*4882a593Smuzhiyun 					"Failed GPIO request for dok: %d err %d\n",
239*4882a593Smuzhiyun 					pdata->dok, ret);
240*4882a593Smuzhiyun 				return ret;
241*4882a593Smuzhiyun 			}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 			gpio = pdata->dok; /* PULL_UPed Interrupt */
244*4882a593Smuzhiyun 			ta_in = gpio_get_value(gpio) ? 0 : 1;
245*4882a593Smuzhiyun 		} else {
246*4882a593Smuzhiyun 			dev_err(dev, "When DC is wired, DOK should be wired as well.\n");
247*4882a593Smuzhiyun 			return -EINVAL;
248*4882a593Smuzhiyun 		}
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->dcm)) {
252*4882a593Smuzhiyun 		ret = devm_gpio_request(dev, pdata->dcm, data->psy_desc.name);
253*4882a593Smuzhiyun 		if (ret) {
254*4882a593Smuzhiyun 			dev_err(dev,
255*4882a593Smuzhiyun 				"Failed GPIO request for dcm: %d err %d\n",
256*4882a593Smuzhiyun 				pdata->dcm, ret);
257*4882a593Smuzhiyun 			return ret;
258*4882a593Smuzhiyun 		}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		gpio = pdata->dcm; /* Output */
261*4882a593Smuzhiyun 		gpio_set_value(gpio, ta_in);
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (pdata->usb_valid) {
265*4882a593Smuzhiyun 		if (gpio_is_valid(pdata->uok)) {
266*4882a593Smuzhiyun 			ret = devm_gpio_request(dev, pdata->uok,
267*4882a593Smuzhiyun 						data->psy_desc.name);
268*4882a593Smuzhiyun 			if (ret) {
269*4882a593Smuzhiyun 				dev_err(dev,
270*4882a593Smuzhiyun 					"Failed GPIO request for uok: %d err %d\n",
271*4882a593Smuzhiyun 					pdata->uok, ret);
272*4882a593Smuzhiyun 				return ret;
273*4882a593Smuzhiyun 			}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 			gpio = pdata->uok;
276*4882a593Smuzhiyun 			usb_in = gpio_get_value(gpio) ? 0 : 1;
277*4882a593Smuzhiyun 		} else {
278*4882a593Smuzhiyun 			dev_err(dev, "When USB is wired, UOK should be wired."
279*4882a593Smuzhiyun 					"as well.\n");
280*4882a593Smuzhiyun 			return -EINVAL;
281*4882a593Smuzhiyun 		}
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->cen)) {
285*4882a593Smuzhiyun 		ret = devm_gpio_request(dev, pdata->cen, data->psy_desc.name);
286*4882a593Smuzhiyun 		if (ret) {
287*4882a593Smuzhiyun 			dev_err(dev,
288*4882a593Smuzhiyun 				"Failed GPIO request for cen: %d err %d\n",
289*4882a593Smuzhiyun 				pdata->cen, ret);
290*4882a593Smuzhiyun 			return ret;
291*4882a593Smuzhiyun 		}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 		gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1);
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->chg)) {
297*4882a593Smuzhiyun 		ret = devm_gpio_request(dev, pdata->chg, data->psy_desc.name);
298*4882a593Smuzhiyun 		if (ret) {
299*4882a593Smuzhiyun 			dev_err(dev,
300*4882a593Smuzhiyun 				"Failed GPIO request for chg: %d err %d\n",
301*4882a593Smuzhiyun 				pdata->chg, ret);
302*4882a593Smuzhiyun 			return ret;
303*4882a593Smuzhiyun 		}
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->flt)) {
307*4882a593Smuzhiyun 		ret = devm_gpio_request(dev, pdata->flt, data->psy_desc.name);
308*4882a593Smuzhiyun 		if (ret) {
309*4882a593Smuzhiyun 			dev_err(dev,
310*4882a593Smuzhiyun 				"Failed GPIO request for flt: %d err %d\n",
311*4882a593Smuzhiyun 				pdata->flt, ret);
312*4882a593Smuzhiyun 			return ret;
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->usus)) {
317*4882a593Smuzhiyun 		ret = devm_gpio_request(dev, pdata->usus, data->psy_desc.name);
318*4882a593Smuzhiyun 		if (ret) {
319*4882a593Smuzhiyun 			dev_err(dev,
320*4882a593Smuzhiyun 				"Failed GPIO request for usus: %d err %d\n",
321*4882a593Smuzhiyun 				pdata->usus, ret);
322*4882a593Smuzhiyun 			return ret;
323*4882a593Smuzhiyun 		}
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	data->fault = false;
327*4882a593Smuzhiyun 	data->ta_in = ta_in;
328*4882a593Smuzhiyun 	data->usb_in = usb_in;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	return 0;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
max8903_probe(struct platform_device * pdev)333*4882a593Smuzhiyun static int max8903_probe(struct platform_device *pdev)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	struct max8903_data *data;
336*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
337*4882a593Smuzhiyun 	struct max8903_pdata *pdata = pdev->dev.platform_data;
338*4882a593Smuzhiyun 	struct power_supply_config psy_cfg = {};
339*4882a593Smuzhiyun 	int ret = 0;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
342*4882a593Smuzhiyun 	if (!data)
343*4882a593Smuzhiyun 		return -ENOMEM;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	if (IS_ENABLED(CONFIG_OF) && !pdata && dev->of_node)
346*4882a593Smuzhiyun 		pdata = max8903_parse_dt_data(dev);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (!pdata) {
349*4882a593Smuzhiyun 		dev_err(dev, "No platform data.\n");
350*4882a593Smuzhiyun 		return -EINVAL;
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	pdev->dev.platform_data = pdata;
354*4882a593Smuzhiyun 	data->pdata = pdata;
355*4882a593Smuzhiyun 	data->dev = dev;
356*4882a593Smuzhiyun 	platform_set_drvdata(pdev, data);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if (pdata->dc_valid == false && pdata->usb_valid == false) {
359*4882a593Smuzhiyun 		dev_err(dev, "No valid power sources.\n");
360*4882a593Smuzhiyun 		return -EINVAL;
361*4882a593Smuzhiyun 	}
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	ret = max8903_setup_gpios(pdev);
364*4882a593Smuzhiyun 	if (ret)
365*4882a593Smuzhiyun 		return ret;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	data->psy_desc.name = "max8903_charger";
368*4882a593Smuzhiyun 	data->psy_desc.type = (data->ta_in) ? POWER_SUPPLY_TYPE_MAINS :
369*4882a593Smuzhiyun 			((data->usb_in) ? POWER_SUPPLY_TYPE_USB :
370*4882a593Smuzhiyun 			 POWER_SUPPLY_TYPE_BATTERY);
371*4882a593Smuzhiyun 	data->psy_desc.get_property = max8903_get_property;
372*4882a593Smuzhiyun 	data->psy_desc.properties = max8903_charger_props;
373*4882a593Smuzhiyun 	data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	psy_cfg.of_node = dev->of_node;
376*4882a593Smuzhiyun 	psy_cfg.drv_data = data;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg);
379*4882a593Smuzhiyun 	if (IS_ERR(data->psy)) {
380*4882a593Smuzhiyun 		dev_err(dev, "failed: power supply register.\n");
381*4882a593Smuzhiyun 		return PTR_ERR(data->psy);
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (pdata->dc_valid) {
385*4882a593Smuzhiyun 		ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->dok),
386*4882a593Smuzhiyun 					NULL, max8903_dcin,
387*4882a593Smuzhiyun 					IRQF_TRIGGER_FALLING |
388*4882a593Smuzhiyun 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
389*4882a593Smuzhiyun 					"MAX8903 DC IN", data);
390*4882a593Smuzhiyun 		if (ret) {
391*4882a593Smuzhiyun 			dev_err(dev, "Cannot request irq %d for DC (%d)\n",
392*4882a593Smuzhiyun 					gpio_to_irq(pdata->dok), ret);
393*4882a593Smuzhiyun 			return ret;
394*4882a593Smuzhiyun 		}
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (pdata->usb_valid) {
398*4882a593Smuzhiyun 		ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->uok),
399*4882a593Smuzhiyun 					NULL, max8903_usbin,
400*4882a593Smuzhiyun 					IRQF_TRIGGER_FALLING |
401*4882a593Smuzhiyun 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
402*4882a593Smuzhiyun 					"MAX8903 USB IN", data);
403*4882a593Smuzhiyun 		if (ret) {
404*4882a593Smuzhiyun 			dev_err(dev, "Cannot request irq %d for USB (%d)\n",
405*4882a593Smuzhiyun 					gpio_to_irq(pdata->uok), ret);
406*4882a593Smuzhiyun 			return ret;
407*4882a593Smuzhiyun 		}
408*4882a593Smuzhiyun 	}
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	if (gpio_is_valid(pdata->flt)) {
411*4882a593Smuzhiyun 		ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt),
412*4882a593Smuzhiyun 					NULL, max8903_fault,
413*4882a593Smuzhiyun 					IRQF_TRIGGER_FALLING |
414*4882a593Smuzhiyun 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
415*4882a593Smuzhiyun 					"MAX8903 Fault", data);
416*4882a593Smuzhiyun 		if (ret) {
417*4882a593Smuzhiyun 			dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
418*4882a593Smuzhiyun 					gpio_to_irq(pdata->flt), ret);
419*4882a593Smuzhiyun 			return ret;
420*4882a593Smuzhiyun 		}
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	return 0;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun static const struct of_device_id max8903_match_ids[] = {
427*4882a593Smuzhiyun 	{ .compatible = "maxim,max8903", },
428*4882a593Smuzhiyun 	{ /* sentinel */ }
429*4882a593Smuzhiyun };
430*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, max8903_match_ids);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun static struct platform_driver max8903_driver = {
433*4882a593Smuzhiyun 	.probe	= max8903_probe,
434*4882a593Smuzhiyun 	.driver = {
435*4882a593Smuzhiyun 		.name	= "max8903-charger",
436*4882a593Smuzhiyun 		.of_match_table = max8903_match_ids
437*4882a593Smuzhiyun 	},
438*4882a593Smuzhiyun };
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun module_platform_driver(max8903_driver);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun MODULE_LICENSE("GPL");
443*4882a593Smuzhiyun MODULE_DESCRIPTION("MAX8903 Charger Driver");
444*4882a593Smuzhiyun MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
445*4882a593Smuzhiyun MODULE_ALIAS("platform:max8903-charger");
446