Merge remote-tracking branch 'selinux/next'
[deliverable/linux.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");
This page took 0.072807 seconds and 5 git commands to generate.