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