]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/power/max8925_power.c
max8925_power: Do not detect ac insert if handled by other code
[karo-tx-linux.git] / drivers / power / max8925_power.c
1 /*
2  * Battery driver for Maxim MAX8925
3  *
4  * Copyright (c) 2009-2010 Marvell International Ltd.
5  *      Haojian Zhuang <haojian.zhuang@marvell.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 version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/module.h>
13 #include <linux/err.h>
14 #include <linux/slab.h>
15 #include <linux/i2c.h>
16 #include <linux/interrupt.h>
17 #include <linux/platform_device.h>
18 #include <linux/power_supply.h>
19 #include <linux/mfd/max8925.h>
20
21 /* registers in GPM */
22 #define MAX8925_OUT5VEN                 0x54
23 #define MAX8925_OUT3VEN                 0x58
24 #define MAX8925_CHG_CNTL1               0x7c
25
26 /* bits definition */
27 #define MAX8925_CHG_STAT_VSYSLOW        (1 << 0)
28 #define MAX8925_CHG_STAT_MODE_MASK      (3 << 2)
29 #define MAX8925_CHG_STAT_EN_MASK        (1 << 4)
30 #define MAX8925_CHG_MBDET               (1 << 1)
31 #define MAX8925_CHG_AC_RANGE_MASK       (3 << 6)
32
33 /* registers in ADC */
34 #define MAX8925_ADC_RES_CNFG1           0x06
35 #define MAX8925_ADC_AVG_CNFG1           0x07
36 #define MAX8925_ADC_ACQ_CNFG1           0x08
37 #define MAX8925_ADC_ACQ_CNFG2           0x09
38 /* 2 bytes registers in below. MSB is 1st, LSB is 2nd. */
39 #define MAX8925_ADC_AUX2                0x62
40 #define MAX8925_ADC_VCHG                0x64
41 #define MAX8925_ADC_VBBATT              0x66
42 #define MAX8925_ADC_VMBATT              0x68
43 #define MAX8925_ADC_ISNS                0x6a
44 #define MAX8925_ADC_THM                 0x6c
45 #define MAX8925_ADC_TDIE                0x6e
46 #define MAX8925_CMD_AUX2                0xc8
47 #define MAX8925_CMD_VCHG                0xd0
48 #define MAX8925_CMD_VBBATT              0xd8
49 #define MAX8925_CMD_VMBATT              0xe0
50 #define MAX8925_CMD_ISNS                0xe8
51 #define MAX8925_CMD_THM                 0xf0
52 #define MAX8925_CMD_TDIE                0xf8
53
54 enum {
55         MEASURE_AUX2,
56         MEASURE_VCHG,
57         MEASURE_VBBATT,
58         MEASURE_VMBATT,
59         MEASURE_ISNS,
60         MEASURE_THM,
61         MEASURE_TDIE,
62         MEASURE_MAX,
63 };
64
65 struct max8925_power_info {
66         struct max8925_chip     *chip;
67         struct i2c_client       *gpm;
68         struct i2c_client       *adc;
69
70         struct power_supply     ac;
71         struct power_supply     usb;
72         struct power_supply     battery;
73         int                     irq_base;
74         unsigned                ac_online:1;
75         unsigned                usb_online:1;
76         unsigned                bat_online:1;
77         unsigned                chg_mode:2;
78         unsigned                batt_detect:1;  /* detecing MB by ID pin */
79         unsigned                topoff_threshold:2;
80         unsigned                fast_charge:3;
81         unsigned                no_temp_support:1;
82         unsigned                no_insert_detect:1;
83
84         int (*set_charger) (int);
85 };
86
87 static int __set_charger(struct max8925_power_info *info, int enable)
88 {
89         struct max8925_chip *chip = info->chip;
90         if (enable) {
91                 /* enable charger in platform */
92                 if (info->set_charger)
93                         info->set_charger(1);
94                 /* enable charger */
95                 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 0);
96         } else {
97                 /* disable charge */
98                 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7);
99                 if (info->set_charger)
100                         info->set_charger(0);
101         }
102         dev_dbg(chip->dev, "%s\n", (enable) ? "Enable charger"
103                 : "Disable charger");
104         return 0;
105 }
106
107 static irqreturn_t max8925_charger_handler(int irq, void *data)
108 {
109         struct max8925_power_info *info = (struct max8925_power_info *)data;
110         struct max8925_chip *chip = info->chip;
111
112         switch (irq - chip->irq_base) {
113         case MAX8925_IRQ_VCHG_DC_R:
114                 info->ac_online = 1;
115                 __set_charger(info, 1);
116                 dev_dbg(chip->dev, "Adapter inserted\n");
117                 break;
118         case MAX8925_IRQ_VCHG_DC_F:
119                 info->ac_online = 0;
120                 __set_charger(info, 0);
121                 dev_dbg(chip->dev, "Adapter removed\n");
122                 break;
123         case MAX8925_IRQ_VCHG_USB_R:
124                 info->usb_online = 1;
125                 __set_charger(info, 1);
126                 dev_dbg(chip->dev, "USB inserted\n");
127                 break;
128         case MAX8925_IRQ_VCHG_USB_F:
129                 info->usb_online = 0;
130                 __set_charger(info, 0);
131                 dev_dbg(chip->dev, "USB removed\n");
132                 break;
133         case MAX8925_IRQ_VCHG_THM_OK_F:
134                 /* Battery is not ready yet */
135                 dev_dbg(chip->dev, "Battery temperature is out of range\n");
136         case MAX8925_IRQ_VCHG_DC_OVP:
137                 dev_dbg(chip->dev, "Error detection\n");
138                 __set_charger(info, 0);
139                 break;
140         case MAX8925_IRQ_VCHG_THM_OK_R:
141                 /* Battery is ready now */
142                 dev_dbg(chip->dev, "Battery temperature is in range\n");
143                 break;
144         case MAX8925_IRQ_VCHG_SYSLOW_R:
145                 /* VSYS is low */
146                 dev_info(chip->dev, "Sys power is too low\n");
147                 break;
148         case MAX8925_IRQ_VCHG_SYSLOW_F:
149                 dev_dbg(chip->dev, "Sys power is above low threshold\n");
150                 break;
151         case MAX8925_IRQ_VCHG_DONE:
152                 __set_charger(info, 0);
153                 dev_dbg(chip->dev, "Charging is done\n");
154                 break;
155         case MAX8925_IRQ_VCHG_TOPOFF:
156                 dev_dbg(chip->dev, "Charging in top-off mode\n");
157                 break;
158         case MAX8925_IRQ_VCHG_TMR_FAULT:
159                 __set_charger(info, 0);
160                 dev_dbg(chip->dev, "Safe timer is expired\n");
161                 break;
162         case MAX8925_IRQ_VCHG_RST:
163                 __set_charger(info, 0);
164                 dev_dbg(chip->dev, "Charger is reset\n");
165                 break;
166         }
167         return IRQ_HANDLED;
168 }
169
170 static int start_measure(struct max8925_power_info *info, int type)
171 {
172         unsigned char buf[2] = {0, 0};
173         int meas_reg = 0, ret;
174
175         switch (type) {
176         case MEASURE_VCHG:
177                 meas_reg = MAX8925_ADC_VCHG;
178                 break;
179         case MEASURE_VBBATT:
180                 meas_reg = MAX8925_ADC_VBBATT;
181                 break;
182         case MEASURE_VMBATT:
183                 meas_reg = MAX8925_ADC_VMBATT;
184                 break;
185         case MEASURE_ISNS:
186                 meas_reg = MAX8925_ADC_ISNS;
187                 break;
188         default:
189                 return -EINVAL;
190         }
191
192         max8925_bulk_read(info->adc, meas_reg, 2, buf);
193         ret = ((buf[0]<<8) | buf[1]) >> 4;
194
195         return ret;
196 }
197
198 static int max8925_ac_get_prop(struct power_supply *psy,
199                                enum power_supply_property psp,
200                                union power_supply_propval *val)
201 {
202         struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
203         int ret = 0;
204
205         switch (psp) {
206         case POWER_SUPPLY_PROP_ONLINE:
207                 val->intval = info->ac_online;
208                 break;
209         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
210                 if (info->ac_online) {
211                         ret = start_measure(info, MEASURE_VCHG);
212                         if (ret >= 0) {
213                                 val->intval = ret * 2000;       /* unit is uV */
214                                 goto out;
215                         }
216                 }
217                 ret = -ENODATA;
218                 break;
219         default:
220                 ret = -ENODEV;
221                 break;
222         }
223 out:
224         return ret;
225 }
226
227 static enum power_supply_property max8925_ac_props[] = {
228         POWER_SUPPLY_PROP_ONLINE,
229         POWER_SUPPLY_PROP_VOLTAGE_NOW,
230 };
231
232 static int max8925_usb_get_prop(struct power_supply *psy,
233                                 enum power_supply_property psp,
234                                 union power_supply_propval *val)
235 {
236         struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
237         int ret = 0;
238
239         switch (psp) {
240         case POWER_SUPPLY_PROP_ONLINE:
241                 val->intval = info->usb_online;
242                 break;
243         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
244                 if (info->usb_online) {
245                         ret = start_measure(info, MEASURE_VCHG);
246                         if (ret >= 0) {
247                                 val->intval = ret * 2000;       /* unit is uV */
248                                 goto out;
249                         }
250                 }
251                 ret = -ENODATA;
252                 break;
253         default:
254                 ret = -ENODEV;
255                 break;
256         }
257 out:
258         return ret;
259 }
260
261 static enum power_supply_property max8925_usb_props[] = {
262         POWER_SUPPLY_PROP_ONLINE,
263         POWER_SUPPLY_PROP_VOLTAGE_NOW,
264 };
265
266 static int max8925_bat_get_prop(struct power_supply *psy,
267                                 enum power_supply_property psp,
268                                 union power_supply_propval *val)
269 {
270         struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
271         int ret = 0;
272
273         switch (psp) {
274         case POWER_SUPPLY_PROP_ONLINE:
275                 val->intval = info->bat_online;
276                 break;
277         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
278                 if (info->bat_online) {
279                         ret = start_measure(info, MEASURE_VMBATT);
280                         if (ret >= 0) {
281                                 val->intval = ret * 2000;       /* unit is uV */
282                                 ret = 0;
283                                 break;
284                         }
285                 }
286                 ret = -ENODATA;
287                 break;
288         case POWER_SUPPLY_PROP_CURRENT_NOW:
289                 if (info->bat_online) {
290                         ret = start_measure(info, MEASURE_ISNS);
291                         if (ret >= 0) {
292                                 /* assume r_sns is 0.02 */
293                                 ret = ((ret * 6250) - 3125) /* uA */;
294                                 val->intval = 0;
295                                 if (ret > 0)
296                                         val->intval = ret; /* unit is mA */
297                                 ret = 0;
298                                 break;
299                         }
300                 }
301                 ret = -ENODATA;
302                 break;
303         case POWER_SUPPLY_PROP_CHARGE_TYPE:
304                 if (!info->bat_online) {
305                         ret = -ENODATA;
306                         break;
307                 }
308                 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
309                 ret = (ret & MAX8925_CHG_STAT_MODE_MASK) >> 2;
310                 switch (ret) {
311                 case 1:
312                         val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
313                         break;
314                 case 0:
315                 case 2:
316                         val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
317                         break;
318                 case 3:
319                         val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
320                         break;
321                 }
322                 ret = 0;
323                 break;
324         case POWER_SUPPLY_PROP_STATUS:
325                 if (!info->bat_online) {
326                         ret = -ENODATA;
327                         break;
328                 }
329                 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
330                 if (info->usb_online || info->ac_online) {
331                         val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
332                         if (ret & MAX8925_CHG_STAT_EN_MASK)
333                                 val->intval = POWER_SUPPLY_STATUS_CHARGING;
334                 } else
335                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
336                 ret = 0;
337                 break;
338         default:
339                 ret = -ENODEV;
340                 break;
341         }
342         return ret;
343 }
344
345 static enum power_supply_property max8925_battery_props[] = {
346         POWER_SUPPLY_PROP_ONLINE,
347         POWER_SUPPLY_PROP_VOLTAGE_NOW,
348         POWER_SUPPLY_PROP_CURRENT_NOW,
349         POWER_SUPPLY_PROP_CHARGE_TYPE,
350         POWER_SUPPLY_PROP_STATUS,
351 };
352
353 #define REQUEST_IRQ(_irq, _name)                                        \
354 do {                                                                    \
355         ret = request_threaded_irq(chip->irq_base + _irq, NULL,         \
356                                     max8925_charger_handler,            \
357                                     IRQF_ONESHOT, _name, info);         \
358         if (ret)                                                        \
359                 dev_err(chip->dev, "Failed to request IRQ #%d: %d\n",   \
360                         _irq, ret);                                     \
361 } while (0)
362
363 static __devinit int max8925_init_charger(struct max8925_chip *chip,
364                                           struct max8925_power_info *info)
365 {
366         int ret;
367
368         REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp");
369         if (!info->no_insert_detect) {
370                 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove");
371                 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert");
372         }
373         REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_OVP, "usb-ovp");
374         REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_F, "usb-remove");
375         REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_R, "usb-insert");
376         if (!info->no_temp_support) {
377                 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range");
378                 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range");
379         }
380         REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high");
381         REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low");
382         REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset");
383         REQUEST_IRQ(MAX8925_IRQ_VCHG_DONE, "charger-done");
384         REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff");
385         REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire");
386
387         info->ac_online = 0;
388         info->usb_online = 0;
389         info->bat_online = 0;
390         ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
391         if (ret >= 0) {
392                 /*
393                  * If battery detection is enabled, ID pin of battery is
394                  * connected to MBDET pin of MAX8925. It could be used to
395                  * detect battery presence.
396                  * Otherwise, we have to assume that battery is always on.
397                  */
398                 if (info->batt_detect)
399                         info->bat_online = (ret & MAX8925_CHG_MBDET) ? 0 : 1;
400                 else
401                         info->bat_online = 1;
402                 if (ret & MAX8925_CHG_AC_RANGE_MASK)
403                         info->ac_online = 1;
404                 else
405                         info->ac_online = 0;
406         }
407         /* disable charge */
408         max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7);
409         /* set charging current in charge topoff mode */
410         max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 3 << 5,
411                          info->topoff_threshold << 5);
412         /* set charing current in fast charge mode */
413         max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 7, info->fast_charge);
414
415         return 0;
416 }
417
418 static __devexit int max8925_deinit_charger(struct max8925_power_info *info)
419 {
420         struct max8925_chip *chip = info->chip;
421         int irq;
422
423         irq = chip->irq_base + MAX8925_IRQ_VCHG_DC_OVP;
424         for (; irq <= chip->irq_base + MAX8925_IRQ_VCHG_TMR_FAULT; irq++)
425                 free_irq(irq, info);
426
427         return 0;
428 }
429
430 static __devinit int max8925_power_probe(struct platform_device *pdev)
431 {
432         struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
433         struct max8925_power_pdata *pdata = NULL;
434         struct max8925_power_info *info;
435         int ret;
436
437         pdata = pdev->dev.platform_data;
438         if (!pdata) {
439                 dev_err(&pdev->dev, "platform data isn't assigned to "
440                         "power supply\n");
441                 return -EINVAL;
442         }
443
444         info = kzalloc(sizeof(struct max8925_power_info), GFP_KERNEL);
445         if (!info)
446                 return -ENOMEM;
447         info->chip = chip;
448         info->gpm = chip->i2c;
449         info->adc = chip->adc;
450         platform_set_drvdata(pdev, info);
451
452         info->ac.name = "max8925-ac";
453         info->ac.type = POWER_SUPPLY_TYPE_MAINS;
454         info->ac.properties = max8925_ac_props;
455         info->ac.num_properties = ARRAY_SIZE(max8925_ac_props);
456         info->ac.get_property = max8925_ac_get_prop;
457         ret = power_supply_register(&pdev->dev, &info->ac);
458         if (ret)
459                 goto out;
460         info->ac.dev->parent = &pdev->dev;
461
462         info->usb.name = "max8925-usb";
463         info->usb.type = POWER_SUPPLY_TYPE_USB;
464         info->usb.properties = max8925_usb_props;
465         info->usb.num_properties = ARRAY_SIZE(max8925_usb_props);
466         info->usb.get_property = max8925_usb_get_prop;
467         ret = power_supply_register(&pdev->dev, &info->usb);
468         if (ret)
469                 goto out_usb;
470         info->usb.dev->parent = &pdev->dev;
471
472         info->battery.name = "max8925-battery";
473         info->battery.type = POWER_SUPPLY_TYPE_BATTERY;
474         info->battery.properties = max8925_battery_props;
475         info->battery.num_properties = ARRAY_SIZE(max8925_battery_props);
476         info->battery.get_property = max8925_bat_get_prop;
477         ret = power_supply_register(&pdev->dev, &info->battery);
478         if (ret)
479                 goto out_battery;
480         info->battery.dev->parent = &pdev->dev;
481
482         info->batt_detect = pdata->batt_detect;
483         info->topoff_threshold = pdata->topoff_threshold;
484         info->fast_charge = pdata->fast_charge;
485         info->set_charger = pdata->set_charger;
486         info->no_temp_support = pdata->no_temp_support;
487         info->no_insert_detect = pdata->no_insert_detect;
488
489         max8925_init_charger(chip, info);
490         return 0;
491 out_battery:
492         power_supply_unregister(&info->battery);
493 out_usb:
494         power_supply_unregister(&info->ac);
495 out:
496         kfree(info);
497         return ret;
498 }
499
500 static __devexit int max8925_power_remove(struct platform_device *pdev)
501 {
502         struct max8925_power_info *info = platform_get_drvdata(pdev);
503
504         if (info) {
505                 power_supply_unregister(&info->ac);
506                 power_supply_unregister(&info->usb);
507                 power_supply_unregister(&info->battery);
508                 max8925_deinit_charger(info);
509                 kfree(info);
510         }
511         return 0;
512 }
513
514 static struct platform_driver max8925_power_driver = {
515         .probe  = max8925_power_probe,
516         .remove = __devexit_p(max8925_power_remove),
517         .driver = {
518                 .name   = "max8925-power",
519         },
520 };
521
522 static int __init max8925_power_init(void)
523 {
524         return platform_driver_register(&max8925_power_driver);
525 }
526 module_init(max8925_power_init);
527
528 static void __exit max8925_power_exit(void)
529 {
530         platform_driver_unregister(&max8925_power_driver);
531 }
532 module_exit(max8925_power_exit);
533
534 MODULE_LICENSE("GPL");
535 MODULE_DESCRIPTION("Power supply driver for MAX8925");
536 MODULE_ALIAS("platform:max8925-power");