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