xref: /openbmc/linux/drivers/power/supply/qcom_smbb.c (revision e983940270f10fe8551baf0098be76ea478294a3)
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");
973