Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux...
[linux/fpc-iii.git] / drivers / power / qcom_smbb.c
blob5eb1e9e543e2a3cfbf50570a35c213b5c1a831e8
1 /* Copyright (c) 2014, Sony Mobile Communications Inc.
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.
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.
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.
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
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>
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)
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
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)
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)
81 #define SMBB_DC_IMAX 0x444
83 #define SMBB_MISC_REV2 0x601
84 #define SMBB_MISC_BOOT_DONE 0x642
85 #define BOOT_DONE BIT(7)
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 */
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,
110 struct smbb_charger {
111 unsigned int revision;
112 unsigned int addr;
113 struct device *dev;
115 bool dc_disabled;
116 bool jeita_ext_temp;
117 unsigned long status;
118 struct mutex statlock;
120 unsigned int attr[_ATTR_CNT];
122 struct power_supply *usb_psy;
123 struct power_supply *dc_psy;
124 struct power_supply *bat_psy;
125 struct regmap *regmap;
128 static int smbb_vbat_weak_fn(unsigned int index)
130 return 2100000 + index * 100000;
133 static int smbb_vin_fn(unsigned int index)
135 if (index > 42)
136 return 5600000 + (index - 43) * 200000;
137 return 3400000 + index * 50000;
140 static int smbb_vmax_fn(unsigned int index)
142 return 3240000 + index * 10000;
145 static int smbb_vbat_det_fn(unsigned int index)
147 return 3240000 + index * 20000;
150 static int smbb_imax_fn(unsigned int index)
152 if (index < 2)
153 return 100000 + index * 50000;
154 return index * 100000;
157 static int smbb_bat_imax_fn(unsigned int index)
159 return index * 50000;
162 static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int))
164 unsigned int widx;
165 unsigned int sel;
167 for (widx = sel = 0; (*fn)(widx) <= val; ++widx)
168 sel = widx;
170 return sel;
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,
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,
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,
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,
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,
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,
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,
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,
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,
251 static int smbb_charger_attr_write(struct smbb_charger *chg,
252 enum smbb_attr which, unsigned int val)
254 const struct smbb_charger_attr *prop;
255 unsigned int wval;
256 unsigned int out;
257 int rc;
259 prop = &smbb_charger_attrs[which];
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;
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;
277 wval = prop->hw_fn(wval);
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;
287 wval = smbb_hw_lookup(val, prop->hw_fn);
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;
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);
301 dev_dbg(chg->dev, "%s <= %d\n", prop->name, out);
303 chg->attr[which] = out;
305 return 0;
308 static int smbb_charger_attr_read(struct smbb_charger *chg,
309 enum smbb_attr which)
311 const struct smbb_charger_attr *prop;
312 unsigned int val;
313 int rc;
315 prop = &smbb_charger_attrs[which];
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;
322 val = prop->hw_fn(val);
323 dev_dbg(chg->dev, "%s => %d\n", prop->name, val);
325 chg->attr[which] = val;
327 return 0;
330 static int smbb_charger_attr_parse(struct smbb_charger *chg,
331 enum smbb_attr which)
333 const struct smbb_charger_attr *prop;
334 unsigned int val;
335 int rc;
337 prop = &smbb_charger_attrs[which];
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;
345 return smbb_charger_attr_read(chg, which);
348 static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag)
350 bool state;
351 int ret;
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;
359 mutex_lock(&chg->statlock);
360 if (state)
361 chg->status |= flag;
362 else
363 chg->status &= ~flag;
364 mutex_unlock(&chg->statlock);
366 dev_dbg(chg->dev, "status = %03lx\n", chg->status);
369 static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
371 struct smbb_charger *chg = _data;
373 smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID);
374 power_supply_changed(chg->usb_psy);
376 return IRQ_HANDLED;
379 static irqreturn_t smbb_dc_valid_handler(int irq, void *_data)
381 struct smbb_charger *chg = _data;
383 smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID);
384 if (!chg->dc_disabled)
385 power_supply_changed(chg->dc_psy);
387 return IRQ_HANDLED;
390 static irqreturn_t smbb_bat_temp_handler(int irq, void *_data)
392 struct smbb_charger *chg = _data;
393 unsigned int val;
394 int rc;
396 rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val);
397 if (rc)
398 return IRQ_HANDLED;
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;
408 mutex_unlock(&chg->statlock);
410 power_supply_changed(chg->bat_psy);
411 return IRQ_HANDLED;
414 static irqreturn_t smbb_bat_present_handler(int irq, void *_data)
416 struct smbb_charger *chg = _data;
418 smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT);
419 power_supply_changed(chg->bat_psy);
421 return IRQ_HANDLED;
424 static irqreturn_t smbb_chg_done_handler(int irq, void *_data)
426 struct smbb_charger *chg = _data;
428 smbb_set_line_flag(chg, irq, STATUS_CHG_DONE);
429 power_supply_changed(chg->bat_psy);
431 return IRQ_HANDLED;
434 static irqreturn_t smbb_chg_gone_handler(int irq, void *_data)
436 struct smbb_charger *chg = _data;
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);
444 return IRQ_HANDLED;
447 static irqreturn_t smbb_chg_fast_handler(int irq, void *_data)
449 struct smbb_charger *chg = _data;
451 smbb_set_line_flag(chg, irq, STATUS_CHG_FAST);
452 power_supply_changed(chg->bat_psy);
454 return IRQ_HANDLED;
457 static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data)
459 struct smbb_charger *chg = _data;
461 smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL);
462 power_supply_changed(chg->bat_psy);
464 return IRQ_HANDLED;
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 },
481 static int smbb_usbin_get_property(struct power_supply *psy,
482 enum power_supply_property psp,
483 union power_supply_propval *val)
485 struct smbb_charger *chg = power_supply_get_drvdata(psy);
486 int rc = 0;
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;
506 return rc;
509 static int smbb_usbin_set_property(struct power_supply *psy,
510 enum power_supply_property psp,
511 const union power_supply_propval *val)
513 struct smbb_charger *chg = power_supply_get_drvdata(psy);
514 int rc;
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;
526 return rc;
529 static int smbb_dcin_get_property(struct power_supply *psy,
530 enum power_supply_property psp,
531 union power_supply_propval *val)
533 struct smbb_charger *chg = power_supply_get_drvdata(psy);
534 int rc = 0;
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;
554 return rc;
557 static int smbb_dcin_set_property(struct power_supply *psy,
558 enum power_supply_property psp,
559 const union power_supply_propval *val)
561 struct smbb_charger *chg = power_supply_get_drvdata(psy);
562 int rc;
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;
574 return rc;
577 static int smbb_charger_writable_property(struct power_supply *psy,
578 enum power_supply_property psp)
580 return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
583 static int smbb_battery_get_property(struct power_supply *psy,
584 enum power_supply_property psp,
585 union power_supply_propval *val)
587 struct smbb_charger *chg = power_supply_get_drvdata(psy);
588 unsigned long status;
589 int rc = 0;
591 mutex_lock(&chg->statlock);
592 status = chg->status;
593 mutex_unlock(&chg->statlock);
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.
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;
650 return rc;
653 static int smbb_battery_set_property(struct power_supply *psy,
654 enum power_supply_property psp,
655 const union power_supply_propval *val)
657 struct smbb_charger *chg = power_supply_get_drvdata(psy);
658 int rc;
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;
672 return rc;
675 static int smbb_battery_writable_property(struct power_supply *psy,
676 enum power_supply_property psp)
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;
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,
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,
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 },
713 /* Disable software timer */
714 { SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
716 /* Clear and disable watchdog */
717 { SMBB_CHG_WDOG_TIME, 0xff, 160 },
718 { SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
720 /* Use charger based EoC detection */
721 { SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
723 /* Disable GSM PA load adjustment.
724 * The PA signal is incorrectly connected on v2.
726 { SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
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 },
731 /* Enable battery temperature comparators */
732 { SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
734 /* Stop USB enumeration timer */
735 { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
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
742 /* Stop USB enumeration timer, again */
743 { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
745 /* Enable charging */
746 { SMBB_CHG_CTRL, CTRL_EN, CTRL_EN },
749 static char *smbb_bif[] = { "smbb-bif" };
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,
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,
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,
781 static int smbb_charger_probe(struct platform_device *pdev)
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;
789 chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
790 if (!chg)
791 return -ENOMEM;
793 chg->dev = &pdev->dev;
794 mutex_init(&chg->statlock);
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;
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;
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;
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;
819 dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
821 chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
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;
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);
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);
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);
865 for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
866 int irq;
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;
875 smbb_charger_irqs[i].handler(irq, chg);
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;
887 chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
888 "qcom,jeita-extended-temp-range");
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;
903 for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
904 const struct reg_off_mask_default *r = &smbb_charger_setup[i];
906 if (r->rev_mask & BIT(chg->revision))
907 continue;
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;
918 platform_set_drvdata(pdev, chg);
920 return 0;
923 static int smbb_charger_remove(struct platform_device *pdev)
925 struct smbb_charger *chg;
927 chg = platform_get_drvdata(pdev);
929 regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
931 return 0;
934 static const struct of_device_id smbb_charger_id_table[] = {
935 { .compatible = "qcom,pm8941-charger" },
938 MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
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,
948 module_platform_driver(smbb_charger_driver);
950 MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
951 MODULE_LICENSE("GPL v2");