]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/power/qcom_smbb.c
next-20150925/battery
[karo-tx-linux.git] / drivers / power / qcom_smbb.c
1 /* Copyright (c) 2014, Sony Mobile Communications Inc.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 and
5  * only version 2 as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * This driver is for the multi-block Switch-Mode Battery Charger and Boost
13  * (SMBB) hardware, found in Qualcomm PM8941 PMICs.  The charger is an
14  * integrated, single-cell lithium-ion battery charger.
15  *
16  * Sub-components:
17  *  - Charger core
18  *  - Buck
19  *  - DC charge-path
20  *  - USB charge-path
21  *  - Battery interface
22  *  - Boost (not implemented)
23  *  - Misc
24  *  - HF-Buck
25  */
26
27 #include <linux/errno.h>
28 #include <linux/interrupt.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/mutex.h>
32 #include <linux/of.h>
33 #include <linux/platform_device.h>
34 #include <linux/power_supply.h>
35 #include <linux/regmap.h>
36 #include <linux/slab.h>
37
38 #define SMBB_CHG_VMAX           0x040
39 #define SMBB_CHG_VSAFE          0x041
40 #define SMBB_CHG_CFG            0x043
41 #define SMBB_CHG_IMAX           0x044
42 #define SMBB_CHG_ISAFE          0x045
43 #define SMBB_CHG_VIN_MIN        0x047
44 #define SMBB_CHG_CTRL           0x049
45 #define CTRL_EN                 BIT(7)
46 #define SMBB_CHG_VBAT_WEAK      0x052
47 #define SMBB_CHG_IBAT_TERM_CHG  0x05b
48 #define IBAT_TERM_CHG_IEOC      BIT(7)
49 #define IBAT_TERM_CHG_IEOC_BMS  BIT(7)
50 #define IBAT_TERM_CHG_IEOC_CHG  0
51 #define SMBB_CHG_VBAT_DET       0x05d
52 #define SMBB_CHG_TCHG_MAX_EN    0x060
53 #define TCHG_MAX_EN             BIT(7)
54 #define SMBB_CHG_WDOG_TIME      0x062
55 #define SMBB_CHG_WDOG_EN        0x065
56 #define WDOG_EN                 BIT(7)
57
58 #define SMBB_BUCK_REG_MODE      0x174
59 #define BUCK_REG_MODE           BIT(0)
60 #define BUCK_REG_MODE_VBAT      BIT(0)
61 #define BUCK_REG_MODE_VSYS      0
62
63 #define SMBB_BAT_PRES_STATUS    0x208
64 #define PRES_STATUS_BAT_PRES    BIT(7)
65 #define SMBB_BAT_TEMP_STATUS    0x209
66 #define TEMP_STATUS_OK          BIT(7)
67 #define TEMP_STATUS_HOT         BIT(6)
68 #define SMBB_BAT_BTC_CTRL       0x249
69 #define BTC_CTRL_COMP_EN        BIT(7)
70 #define BTC_CTRL_COLD_EXT       BIT(1)
71 #define BTC_CTRL_HOT_EXT_N      BIT(0)
72
73 #define SMBB_USB_IMAX           0x344
74 #define SMBB_USB_ENUM_TIMER_STOP 0x34e
75 #define ENUM_TIMER_STOP         BIT(0)
76 #define SMBB_USB_SEC_ACCESS     0x3d0
77 #define SEC_ACCESS_MAGIC        0xa5
78 #define SMBB_USB_REV_BST        0x3ed
79 #define REV_BST_CHG_GONE        BIT(7)
80
81 #define SMBB_DC_IMAX            0x444
82
83 #define SMBB_MISC_REV2          0x601
84 #define SMBB_MISC_BOOT_DONE     0x642
85 #define BOOT_DONE               BIT(7)
86
87 #define STATUS_USBIN_VALID      BIT(0) /* USB connection is valid */
88 #define STATUS_DCIN_VALID       BIT(1) /* DC connection is valid */
89 #define STATUS_BAT_HOT          BIT(2) /* Battery temp 1=Hot, 0=Cold */
90 #define STATUS_BAT_OK           BIT(3) /* Battery temp OK */
91 #define STATUS_BAT_PRESENT      BIT(4) /* Battery is present */
92 #define STATUS_CHG_DONE         BIT(5) /* Charge cycle is complete */
93 #define STATUS_CHG_TRKL         BIT(6) /* Trickle charging */
94 #define STATUS_CHG_FAST         BIT(7) /* Fast charging */
95 #define STATUS_CHG_GONE         BIT(8) /* No charger is connected */
96
97 enum smbb_attr {
98         ATTR_BAT_ISAFE,
99         ATTR_BAT_IMAX,
100         ATTR_USBIN_IMAX,
101         ATTR_DCIN_IMAX,
102         ATTR_BAT_VSAFE,
103         ATTR_BAT_VMAX,
104         ATTR_BAT_VMIN,
105         ATTR_CHG_VDET,
106         ATTR_VIN_MIN,
107         _ATTR_CNT,
108 };
109
110 struct smbb_charger {
111         unsigned int revision;
112         unsigned int addr;
113         struct device *dev;
114
115         bool dc_disabled;
116         bool jeita_ext_temp;
117         unsigned long status;
118         struct mutex statlock;
119
120         unsigned int attr[_ATTR_CNT];
121
122         struct power_supply *usb_psy;
123         struct power_supply *dc_psy;
124         struct power_supply *bat_psy;
125         struct regmap *regmap;
126 };
127
128 static int smbb_vbat_weak_fn(unsigned int index)
129 {
130         return 2100000 + index * 100000;
131 }
132
133 static int smbb_vin_fn(unsigned int index)
134 {
135         if (index > 42)
136                 return 5600000 + (index - 43) * 200000;
137         return 3400000 + index * 50000;
138 }
139
140 static int smbb_vmax_fn(unsigned int index)
141 {
142         return 3240000 + index * 10000;
143 }
144
145 static int smbb_vbat_det_fn(unsigned int index)
146 {
147         return 3240000 + index * 20000;
148 }
149
150 static int smbb_imax_fn(unsigned int index)
151 {
152         if (index < 2)
153                 return 100000 + index * 50000;
154         return index * 100000;
155 }
156
157 static int smbb_bat_imax_fn(unsigned int index)
158 {
159         return index * 50000;
160 }
161
162 static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int))
163 {
164         unsigned int widx;
165         unsigned int sel;
166
167         for (widx = sel = 0; (*fn)(widx) <= val; ++widx)
168                 sel = widx;
169
170         return sel;
171 }
172
173 static const struct smbb_charger_attr {
174         const char *name;
175         unsigned int reg;
176         unsigned int safe_reg;
177         unsigned int max;
178         unsigned int min;
179         unsigned int fail_ok;
180         int (*hw_fn)(unsigned int);
181 } smbb_charger_attrs[] = {
182         [ATTR_BAT_ISAFE] = {
183                 .name = "qcom,fast-charge-safe-current",
184                 .reg = SMBB_CHG_ISAFE,
185                 .max = 3000000,
186                 .min = 200000,
187                 .hw_fn = smbb_bat_imax_fn,
188                 .fail_ok = 1,
189         },
190         [ATTR_BAT_IMAX] = {
191                 .name = "qcom,fast-charge-current-limit",
192                 .reg = SMBB_CHG_IMAX,
193                 .safe_reg = SMBB_CHG_ISAFE,
194                 .max = 3000000,
195                 .min = 200000,
196                 .hw_fn = smbb_bat_imax_fn,
197         },
198         [ATTR_DCIN_IMAX] = {
199                 .name = "qcom,dc-current-limit",
200                 .reg = SMBB_DC_IMAX,
201                 .max = 2500000,
202                 .min = 100000,
203                 .hw_fn = smbb_imax_fn,
204         },
205         [ATTR_BAT_VSAFE] = {
206                 .name = "qcom,fast-charge-safe-voltage",
207                 .reg = SMBB_CHG_VSAFE,
208                 .max = 5000000,
209                 .min = 3240000,
210                 .hw_fn = smbb_vmax_fn,
211                 .fail_ok = 1,
212         },
213         [ATTR_BAT_VMAX] = {
214                 .name = "qcom,fast-charge-high-threshold-voltage",
215                 .reg = SMBB_CHG_VMAX,
216                 .safe_reg = SMBB_CHG_VSAFE,
217                 .max = 5000000,
218                 .min = 3240000,
219                 .hw_fn = smbb_vmax_fn,
220         },
221         [ATTR_BAT_VMIN] = {
222                 .name = "qcom,fast-charge-low-threshold-voltage",
223                 .reg = SMBB_CHG_VBAT_WEAK,
224                 .max = 3600000,
225                 .min = 2100000,
226                 .hw_fn = smbb_vbat_weak_fn,
227         },
228         [ATTR_CHG_VDET] = {
229                 .name = "qcom,auto-recharge-threshold-voltage",
230                 .reg = SMBB_CHG_VBAT_DET,
231                 .max = 5000000,
232                 .min = 3240000,
233                 .hw_fn = smbb_vbat_det_fn,
234         },
235         [ATTR_VIN_MIN] = {
236                 .name = "qcom,minimum-input-voltage",
237                 .reg = SMBB_CHG_VIN_MIN,
238                 .max = 9600000,
239                 .min = 4200000,
240                 .hw_fn = smbb_vin_fn,
241         },
242         [ATTR_USBIN_IMAX] = {
243                 .name = "usb-charge-current-limit",
244                 .reg = SMBB_USB_IMAX,
245                 .max = 2500000,
246                 .min = 100000,
247                 .hw_fn = smbb_imax_fn,
248         },
249 };
250
251 static int smbb_charger_attr_write(struct smbb_charger *chg,
252                 enum smbb_attr which, unsigned int val)
253 {
254         const struct smbb_charger_attr *prop;
255         unsigned int wval;
256         unsigned int out;
257         int rc;
258
259         prop = &smbb_charger_attrs[which];
260
261         if (val > prop->max || val < prop->min) {
262                 dev_err(chg->dev, "value out of range for %s [%u:%u]\n",
263                         prop->name, prop->min, prop->max);
264                 return -EINVAL;
265         }
266
267         if (prop->safe_reg) {
268                 rc = regmap_read(chg->regmap,
269                                 chg->addr + prop->safe_reg, &wval);
270                 if (rc) {
271                         dev_err(chg->dev,
272                                 "unable to read safe value for '%s'\n",
273                                 prop->name);
274                         return rc;
275                 }
276
277                 wval = prop->hw_fn(wval);
278
279                 if (val > wval) {
280                         dev_warn(chg->dev,
281                                 "%s above safe value, clamping at %u\n",
282                                 prop->name, wval);
283                         val = wval;
284                 }
285         }
286
287         wval = smbb_hw_lookup(val, prop->hw_fn);
288
289         rc = regmap_write(chg->regmap, chg->addr + prop->reg, wval);
290         if (rc) {
291                 dev_err(chg->dev, "unable to update %s", prop->name);
292                 return rc;
293         }
294         out = prop->hw_fn(wval);
295         if (out != val) {
296                 dev_warn(chg->dev,
297                         "%s inaccurate, rounded to %u\n",
298                         prop->name, out);
299         }
300
301         dev_dbg(chg->dev, "%s <= %d\n", prop->name, out);
302
303         chg->attr[which] = out;
304
305         return 0;
306 }
307
308 static int smbb_charger_attr_read(struct smbb_charger *chg,
309                 enum smbb_attr which)
310 {
311         const struct smbb_charger_attr *prop;
312         unsigned int val;
313         int rc;
314
315         prop = &smbb_charger_attrs[which];
316
317         rc = regmap_read(chg->regmap, chg->addr + prop->reg, &val);
318         if (rc) {
319                 dev_err(chg->dev, "failed to read %s\n", prop->name);
320                 return rc;
321         }
322         val = prop->hw_fn(val);
323         dev_dbg(chg->dev, "%s => %d\n", prop->name, val);
324
325         chg->attr[which] = val;
326
327         return 0;
328 }
329
330 static int smbb_charger_attr_parse(struct smbb_charger *chg,
331                 enum smbb_attr which)
332 {
333         const struct smbb_charger_attr *prop;
334         unsigned int val;
335         int rc;
336
337         prop = &smbb_charger_attrs[which];
338
339         rc = of_property_read_u32(chg->dev->of_node, prop->name, &val);
340         if (rc == 0) {
341                 rc = smbb_charger_attr_write(chg, which, val);
342                 if (!rc || !prop->fail_ok)
343                         return rc;
344         }
345         return smbb_charger_attr_read(chg, which);
346 }
347
348 static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag)
349 {
350         bool state;
351         int ret;
352
353         ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, &state);
354         if (ret < 0) {
355                 dev_err(chg->dev, "failed to read irq line\n");
356                 return;
357         }
358
359         mutex_lock(&chg->statlock);
360         if (state)
361                 chg->status |= flag;
362         else
363                 chg->status &= ~flag;
364         mutex_unlock(&chg->statlock);
365
366         dev_dbg(chg->dev, "status = %03lx\n", chg->status);
367 }
368
369 static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
370 {
371         struct smbb_charger *chg = _data;
372
373         smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID);
374         power_supply_changed(chg->usb_psy);
375
376         return IRQ_HANDLED;
377 }
378
379 static irqreturn_t smbb_dc_valid_handler(int irq, void *_data)
380 {
381         struct smbb_charger *chg = _data;
382
383         smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID);
384         if (!chg->dc_disabled)
385                 power_supply_changed(chg->dc_psy);
386
387         return IRQ_HANDLED;
388 }
389
390 static irqreturn_t smbb_bat_temp_handler(int irq, void *_data)
391 {
392         struct smbb_charger *chg = _data;
393         unsigned int val;
394         int rc;
395
396         rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val);
397         if (rc)
398                 return IRQ_HANDLED;
399
400         mutex_lock(&chg->statlock);
401         if (val & TEMP_STATUS_OK) {
402                 chg->status |= STATUS_BAT_OK;
403         } else {
404                 chg->status &= ~STATUS_BAT_OK;
405                 if (val & TEMP_STATUS_HOT)
406                         chg->status |= STATUS_BAT_HOT;
407         }
408         mutex_unlock(&chg->statlock);
409
410         power_supply_changed(chg->bat_psy);
411         return IRQ_HANDLED;
412 }
413
414 static irqreturn_t smbb_bat_present_handler(int irq, void *_data)
415 {
416         struct smbb_charger *chg = _data;
417
418         smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT);
419         power_supply_changed(chg->bat_psy);
420
421         return IRQ_HANDLED;
422 }
423
424 static irqreturn_t smbb_chg_done_handler(int irq, void *_data)
425 {
426         struct smbb_charger *chg = _data;
427
428         smbb_set_line_flag(chg, irq, STATUS_CHG_DONE);
429         power_supply_changed(chg->bat_psy);
430
431         return IRQ_HANDLED;
432 }
433
434 static irqreturn_t smbb_chg_gone_handler(int irq, void *_data)
435 {
436         struct smbb_charger *chg = _data;
437
438         smbb_set_line_flag(chg, irq, STATUS_CHG_GONE);
439         power_supply_changed(chg->bat_psy);
440         power_supply_changed(chg->usb_psy);
441         if (!chg->dc_disabled)
442                 power_supply_changed(chg->dc_psy);
443
444         return IRQ_HANDLED;
445 }
446
447 static irqreturn_t smbb_chg_fast_handler(int irq, void *_data)
448 {
449         struct smbb_charger *chg = _data;
450
451         smbb_set_line_flag(chg, irq, STATUS_CHG_FAST);
452         power_supply_changed(chg->bat_psy);
453
454         return IRQ_HANDLED;
455 }
456
457 static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data)
458 {
459         struct smbb_charger *chg = _data;
460
461         smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL);
462         power_supply_changed(chg->bat_psy);
463
464         return IRQ_HANDLED;
465 }
466
467 static const struct smbb_irq {
468         const char *name;
469         irqreturn_t (*handler)(int, void *);
470 } smbb_charger_irqs[] = {
471         { "chg-done", smbb_chg_done_handler },
472         { "chg-fast", smbb_chg_fast_handler },
473         { "chg-trkl", smbb_chg_trkl_handler },
474         { "bat-temp-ok", smbb_bat_temp_handler },
475         { "bat-present", smbb_bat_present_handler },
476         { "chg-gone", smbb_chg_gone_handler },
477         { "usb-valid", smbb_usb_valid_handler },
478         { "dc-valid", smbb_dc_valid_handler },
479 };
480
481 static int smbb_usbin_get_property(struct power_supply *psy,
482                 enum power_supply_property psp,
483                 union power_supply_propval *val)
484 {
485         struct smbb_charger *chg = power_supply_get_drvdata(psy);
486         int rc = 0;
487
488         switch (psp) {
489         case POWER_SUPPLY_PROP_ONLINE:
490                 mutex_lock(&chg->statlock);
491                 val->intval = !(chg->status & STATUS_CHG_GONE) &&
492                                 (chg->status & STATUS_USBIN_VALID);
493                 mutex_unlock(&chg->statlock);
494                 break;
495         case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
496                 val->intval = chg->attr[ATTR_USBIN_IMAX];
497                 break;
498         case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
499                 val->intval = 2500000;
500                 break;
501         default:
502                 rc = -EINVAL;
503                 break;
504         }
505
506         return rc;
507 }
508
509 static int smbb_usbin_set_property(struct power_supply *psy,
510                 enum power_supply_property psp,
511                 const union power_supply_propval *val)
512 {
513         struct smbb_charger *chg = power_supply_get_drvdata(psy);
514         int rc;
515
516         switch (psp) {
517         case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
518                 rc = smbb_charger_attr_write(chg, ATTR_USBIN_IMAX,
519                                 val->intval);
520                 break;
521         default:
522                 rc = -EINVAL;
523                 break;
524         }
525
526         return rc;
527 }
528
529 static int smbb_dcin_get_property(struct power_supply *psy,
530                 enum power_supply_property psp,
531                 union power_supply_propval *val)
532 {
533         struct smbb_charger *chg = power_supply_get_drvdata(psy);
534         int rc = 0;
535
536         switch (psp) {
537         case POWER_SUPPLY_PROP_ONLINE:
538                 mutex_lock(&chg->statlock);
539                 val->intval = !(chg->status & STATUS_CHG_GONE) &&
540                                 (chg->status & STATUS_DCIN_VALID);
541                 mutex_unlock(&chg->statlock);
542                 break;
543         case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
544                 val->intval = chg->attr[ATTR_DCIN_IMAX];
545                 break;
546         case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
547                 val->intval = 2500000;
548                 break;
549         default:
550                 rc = -EINVAL;
551                 break;
552         }
553
554         return rc;
555 }
556
557 static int smbb_dcin_set_property(struct power_supply *psy,
558                 enum power_supply_property psp,
559                 const union power_supply_propval *val)
560 {
561         struct smbb_charger *chg = power_supply_get_drvdata(psy);
562         int rc;
563
564         switch (psp) {
565         case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
566                 rc = smbb_charger_attr_write(chg, ATTR_DCIN_IMAX,
567                                 val->intval);
568                 break;
569         default:
570                 rc = -EINVAL;
571                 break;
572         }
573
574         return rc;
575 }
576
577 static int smbb_charger_writable_property(struct power_supply *psy,
578                 enum power_supply_property psp)
579 {
580         return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
581 }
582
583 static int smbb_battery_get_property(struct power_supply *psy,
584                 enum power_supply_property psp,
585                 union power_supply_propval *val)
586 {
587         struct smbb_charger *chg = power_supply_get_drvdata(psy);
588         unsigned long status;
589         int rc = 0;
590
591         mutex_lock(&chg->statlock);
592         status = chg->status;
593         mutex_unlock(&chg->statlock);
594
595         switch (psp) {
596         case POWER_SUPPLY_PROP_STATUS:
597                 if (status & STATUS_CHG_GONE)
598                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
599                 else if (!(status & (STATUS_DCIN_VALID | STATUS_USBIN_VALID)))
600                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
601                 else if (status & STATUS_CHG_DONE)
602                         val->intval = POWER_SUPPLY_STATUS_FULL;
603                 else if (!(status & STATUS_BAT_OK))
604                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
605                 else if (status & (STATUS_CHG_FAST | STATUS_CHG_TRKL))
606                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
607                 else /* everything is ok for charging, but we are not... */
608                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
609                 break;
610         case POWER_SUPPLY_PROP_HEALTH:
611                 if (status & STATUS_BAT_OK)
612                         val->intval = POWER_SUPPLY_HEALTH_GOOD;
613                 else if (status & STATUS_BAT_HOT)
614                         val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
615                 else
616                         val->intval = POWER_SUPPLY_HEALTH_COLD;
617                 break;
618         case POWER_SUPPLY_PROP_CHARGE_TYPE:
619                 if (status & STATUS_CHG_FAST)
620                         val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
621                 else if (status & STATUS_CHG_TRKL)
622                         val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
623                 else
624                         val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
625                 break;
626         case POWER_SUPPLY_PROP_PRESENT:
627                 val->intval = !!(status & STATUS_BAT_PRESENT);
628                 break;
629         case POWER_SUPPLY_PROP_CURRENT_MAX:
630                 val->intval = chg->attr[ATTR_BAT_IMAX];
631                 break;
632         case POWER_SUPPLY_PROP_VOLTAGE_MAX:
633                 val->intval = chg->attr[ATTR_BAT_VMAX];
634                 break;
635         case POWER_SUPPLY_PROP_TECHNOLOGY:
636                 /* this charger is a single-cell lithium-ion battery charger
637                 * only.  If you hook up some other technology, there will be
638                 * fireworks.
639                 */
640                 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
641                 break;
642         case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
643                 val->intval = 3000000; /* single-cell li-ion low end */
644                 break;
645         default:
646                 rc = -EINVAL;
647                 break;
648         }
649
650         return rc;
651 }
652
653 static int smbb_battery_set_property(struct power_supply *psy,
654                 enum power_supply_property psp,
655                 const union power_supply_propval *val)
656 {
657         struct smbb_charger *chg = power_supply_get_drvdata(psy);
658         int rc;
659
660         switch (psp) {
661         case POWER_SUPPLY_PROP_CURRENT_MAX:
662                 rc = smbb_charger_attr_write(chg, ATTR_BAT_IMAX, val->intval);
663                 break;
664         case POWER_SUPPLY_PROP_VOLTAGE_MAX:
665                 rc = smbb_charger_attr_write(chg, ATTR_BAT_VMAX, val->intval);
666                 break;
667         default:
668                 rc = -EINVAL;
669                 break;
670         }
671
672         return rc;
673 }
674
675 static int smbb_battery_writable_property(struct power_supply *psy,
676                 enum power_supply_property psp)
677 {
678         switch (psp) {
679         case POWER_SUPPLY_PROP_CURRENT_MAX:
680         case POWER_SUPPLY_PROP_VOLTAGE_MAX:
681                 return 1;
682         default:
683                 return 0;
684         }
685 }
686
687 static enum power_supply_property smbb_charger_properties[] = {
688         POWER_SUPPLY_PROP_ONLINE,
689         POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
690         POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
691 };
692
693 static enum power_supply_property smbb_battery_properties[] = {
694         POWER_SUPPLY_PROP_STATUS,
695         POWER_SUPPLY_PROP_HEALTH,
696         POWER_SUPPLY_PROP_PRESENT,
697         POWER_SUPPLY_PROP_CHARGE_TYPE,
698         POWER_SUPPLY_PROP_CURRENT_MAX,
699         POWER_SUPPLY_PROP_VOLTAGE_MAX,
700         POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
701         POWER_SUPPLY_PROP_TECHNOLOGY,
702 };
703
704 static const struct reg_off_mask_default {
705         unsigned int offset;
706         unsigned int mask;
707         unsigned int value;
708         unsigned int rev_mask;
709 } smbb_charger_setup[] = {
710         /* The bootloader is supposed to set this... make sure anyway. */
711         { SMBB_MISC_BOOT_DONE, BOOT_DONE, BOOT_DONE },
712
713         /* Disable software timer */
714         { SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
715
716         /* Clear and disable watchdog */
717         { SMBB_CHG_WDOG_TIME, 0xff, 160 },
718         { SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
719
720         /* Use charger based EoC detection */
721         { SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
722
723         /* Disable GSM PA load adjustment.
724         * The PA signal is incorrectly connected on v2.
725         */
726         { SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
727
728         /* Use VBAT (not VSYS) to compensate for IR drop during fast charging */
729         { SMBB_BUCK_REG_MODE, BUCK_REG_MODE, BUCK_REG_MODE_VBAT },
730
731         /* Enable battery temperature comparators */
732         { SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
733
734         /* Stop USB enumeration timer */
735         { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
736
737 #if 0 /* FIXME supposedly only to disable hardware ARB termination */
738         { SMBB_USB_SEC_ACCESS, SEC_ACCESS_MAGIC },
739         { SMBB_USB_REV_BST, 0xff, REV_BST_CHG_GONE },
740 #endif
741
742         /* Stop USB enumeration timer, again */
743         { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
744
745         /* Enable charging */
746         { SMBB_CHG_CTRL, CTRL_EN, CTRL_EN },
747 };
748
749 static char *smbb_bif[] = { "smbb-bif" };
750
751 static const struct power_supply_desc bat_psy_desc = {
752         .name = "smbb-bif",
753         .type = POWER_SUPPLY_TYPE_BATTERY,
754         .properties = smbb_battery_properties,
755         .num_properties = ARRAY_SIZE(smbb_battery_properties),
756         .get_property = smbb_battery_get_property,
757         .set_property = smbb_battery_set_property,
758         .property_is_writeable = smbb_battery_writable_property,
759 };
760
761 static const struct power_supply_desc usb_psy_desc = {
762         .name = "smbb-usbin",
763         .type = POWER_SUPPLY_TYPE_USB,
764         .properties = smbb_charger_properties,
765         .num_properties = ARRAY_SIZE(smbb_charger_properties),
766         .get_property = smbb_usbin_get_property,
767         .set_property = smbb_usbin_set_property,
768         .property_is_writeable = smbb_charger_writable_property,
769 };
770
771 static const struct power_supply_desc dc_psy_desc = {
772         .name = "smbb-dcin",
773         .type = POWER_SUPPLY_TYPE_MAINS,
774         .properties = smbb_charger_properties,
775         .num_properties = ARRAY_SIZE(smbb_charger_properties),
776         .get_property = smbb_dcin_get_property,
777         .set_property = smbb_dcin_set_property,
778         .property_is_writeable = smbb_charger_writable_property,
779 };
780
781 static int smbb_charger_probe(struct platform_device *pdev)
782 {
783         struct power_supply_config bat_cfg = {};
784         struct power_supply_config usb_cfg = {};
785         struct power_supply_config dc_cfg = {};
786         struct smbb_charger *chg;
787         int rc, i;
788
789         chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
790         if (!chg)
791                 return -ENOMEM;
792
793         chg->dev = &pdev->dev;
794         mutex_init(&chg->statlock);
795
796         chg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
797         if (!chg->regmap) {
798                 dev_err(&pdev->dev, "failed to locate regmap\n");
799                 return -ENODEV;
800         }
801
802         rc = of_property_read_u32(pdev->dev.of_node, "reg", &chg->addr);
803         if (rc) {
804                 dev_err(&pdev->dev, "missing or invalid 'reg' property\n");
805                 return rc;
806         }
807
808         rc = regmap_read(chg->regmap, chg->addr + SMBB_MISC_REV2, &chg->revision);
809         if (rc) {
810                 dev_err(&pdev->dev, "unable to read revision\n");
811                 return rc;
812         }
813
814         chg->revision += 1;
815         if (chg->revision != 2 && chg->revision != 3) {
816                 dev_err(&pdev->dev, "v1 hardware not supported\n");
817                 return -ENODEV;
818         }
819         dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
820
821         chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
822
823         for (i = 0; i < _ATTR_CNT; ++i) {
824                 rc = smbb_charger_attr_parse(chg, i);
825                 if (rc) {
826                         dev_err(&pdev->dev, "failed to parse/apply settings\n");
827                         return rc;
828                 }
829         }
830
831         bat_cfg.drv_data = chg;
832         bat_cfg.of_node = pdev->dev.of_node;
833         chg->bat_psy = devm_power_supply_register(&pdev->dev,
834                                                   &bat_psy_desc,
835                                                   &bat_cfg);
836         if (IS_ERR(chg->bat_psy)) {
837                 dev_err(&pdev->dev, "failed to register battery\n");
838                 return PTR_ERR(chg->bat_psy);
839         }
840
841         usb_cfg.drv_data = chg;
842         usb_cfg.supplied_to = smbb_bif;
843         usb_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
844         chg->usb_psy = devm_power_supply_register(&pdev->dev,
845                                                   &usb_psy_desc,
846                                                   &usb_cfg);
847         if (IS_ERR(chg->usb_psy)) {
848                 dev_err(&pdev->dev, "failed to register USB power supply\n");
849                 return PTR_ERR(chg->usb_psy);
850         }
851
852         if (!chg->dc_disabled) {
853                 dc_cfg.drv_data = chg;
854                 dc_cfg.supplied_to = smbb_bif;
855                 dc_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
856                 chg->dc_psy = devm_power_supply_register(&pdev->dev,
857                                                          &dc_psy_desc,
858                                                          &dc_cfg);
859                 if (IS_ERR(chg->dc_psy)) {
860                         dev_err(&pdev->dev, "failed to register DC power supply\n");
861                         return PTR_ERR(chg->dc_psy);
862                 }
863         }
864
865         for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
866                 int irq;
867
868                 irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name);
869                 if (irq < 0) {
870                         dev_err(&pdev->dev, "failed to get irq '%s'\n",
871                                 smbb_charger_irqs[i].name);
872                         return irq;
873                 }
874
875                 smbb_charger_irqs[i].handler(irq, chg);
876
877                 rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
878                                 smbb_charger_irqs[i].handler, IRQF_ONESHOT,
879                                 smbb_charger_irqs[i].name, chg);
880                 if (rc) {
881                         dev_err(&pdev->dev, "failed to request irq '%s'\n",
882                                 smbb_charger_irqs[i].name);
883                         return rc;
884                 }
885         }
886
887         chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
888                         "qcom,jeita-extended-temp-range");
889
890         /* Set temperature range to [35%:70%] or [25%:80%] accordingly */
891         rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_BAT_BTC_CTRL,
892                         BTC_CTRL_COLD_EXT | BTC_CTRL_HOT_EXT_N,
893                         chg->jeita_ext_temp ?
894                                 BTC_CTRL_COLD_EXT :
895                                 BTC_CTRL_HOT_EXT_N);
896         if (rc) {
897                 dev_err(&pdev->dev,
898                         "unable to set %s temperature range\n",
899                         chg->jeita_ext_temp ? "JEITA extended" : "normal");
900                 return rc;
901         }
902
903         for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
904                 const struct reg_off_mask_default *r = &smbb_charger_setup[i];
905
906                 if (r->rev_mask & BIT(chg->revision))
907                         continue;
908
909                 rc = regmap_update_bits(chg->regmap, chg->addr + r->offset,
910                                 r->mask, r->value);
911                 if (rc) {
912                         dev_err(&pdev->dev,
913                                 "unable to initializing charging, bailing\n");
914                         return rc;
915                 }
916         }
917
918         platform_set_drvdata(pdev, chg);
919
920         return 0;
921 }
922
923 static int smbb_charger_remove(struct platform_device *pdev)
924 {
925         struct smbb_charger *chg;
926
927         chg = platform_get_drvdata(pdev);
928
929         regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
930
931         return 0;
932 }
933
934 static const struct of_device_id smbb_charger_id_table[] = {
935         { .compatible = "qcom,pm8941-charger" },
936         { }
937 };
938 MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
939
940 static struct platform_driver smbb_charger_driver = {
941         .probe    = smbb_charger_probe,
942         .remove  = smbb_charger_remove,
943         .driver  = {
944                 .name   = "qcom-smbb",
945                 .of_match_table = smbb_charger_id_table,
946         },
947 };
948 module_platform_driver(smbb_charger_driver);
949
950 MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
951 MODULE_LICENSE("GPL v2");