Version:  2.0.40 2.2.26 2.4.37 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8

Linux/drivers/power/max8903_charger.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us