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