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