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
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)
57
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
62
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)
72
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)
80
81#define SMBB_DC_IMAX		0x444
82
83#define SMBB_MISC_REV2		0x601
84#define SMBB_MISC_BOOT_DONE	0x642
85#define BOOT_DONE		BIT(7)
86
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 */
96
97enum 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,
108};
109
110struct smbb_charger {
111	unsigned int revision;
112	unsigned int addr;
113	struct device *dev;
114
115	bool dc_disabled;
116	bool jeita_ext_temp;
117	unsigned long status;
118	struct mutex statlock;
119
120	unsigned int attr[_ATTR_CNT];
121
122	struct power_supply *usb_psy;
123	struct power_supply *dc_psy;
124	struct power_supply *bat_psy;
125	struct regmap *regmap;
126};
127
128static int smbb_vbat_weak_fn(unsigned int index)
129{
130	return 2100000 + index * 100000;
131}
132
133static int smbb_vin_fn(unsigned int index)
134{
135	if (index > 42)
136		return 5600000 + (index - 43) * 200000;
137	return 3400000 + index * 50000;
138}
139
140static int smbb_vmax_fn(unsigned int index)
141{
142	return 3240000 + index * 10000;
143}
144
145static int smbb_vbat_det_fn(unsigned int index)
146{
147	return 3240000 + index * 20000;
148}
149
150static int smbb_imax_fn(unsigned int index)
151{
152	if (index < 2)
153		return 100000 + index * 50000;
154	return index * 100000;
155}
156
157static int smbb_bat_imax_fn(unsigned int index)
158{
159	return index * 50000;
160}
161
162static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int))
163{
164	unsigned int widx;
165	unsigned int sel;
166
167	for (widx = sel = 0; (*fn)(widx) <= val; ++widx)
168		sel = widx;
169
170	return sel;
171}
172
173static 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,
189	},
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,
197	},
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,
204	},
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,
212	},
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,
220	},
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,
227	},
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,
234	},
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,
241	},
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,
248	},
249};
250
251static int smbb_charger_attr_write(struct smbb_charger *chg,
252		enum smbb_attr which, unsigned int val)
253{
254	const struct smbb_charger_attr *prop;
255	unsigned int wval;
256	unsigned int out;
257	int rc;
258
259	prop = &smbb_charger_attrs[which];
260
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;
265	}
266
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;
275		}
276
277		wval = prop->hw_fn(wval);
278
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;
284		}
285	}
286
287	wval = smbb_hw_lookup(val, prop->hw_fn);
288
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;
293	}
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);
299	}
300
301	dev_dbg(chg->dev, "%s <= %d\n", prop->name, out);
302
303	chg->attr[which] = out;
304
305	return 0;
306}
307
308static int smbb_charger_attr_read(struct smbb_charger *chg,
309		enum smbb_attr which)
310{
311	const struct smbb_charger_attr *prop;
312	unsigned int val;
313	int rc;
314
315	prop = &smbb_charger_attrs[which];
316
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;
321	}
322	val = prop->hw_fn(val);
323	dev_dbg(chg->dev, "%s => %d\n", prop->name, val);
324
325	chg->attr[which] = val;
326
327	return 0;
328}
329
330static int smbb_charger_attr_parse(struct smbb_charger *chg,
331		enum smbb_attr which)
332{
333	const struct smbb_charger_attr *prop;
334	unsigned int val;
335	int rc;
336
337	prop = &smbb_charger_attrs[which];
338
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;
344	}
345	return smbb_charger_attr_read(chg, which);
346}
347
348static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag)
349{
350	bool state;
351	int ret;
352
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;
357	}
358
359	mutex_lock(&chg->statlock);
360	if (state)
361		chg->status |= flag;
362	else
363		chg->status &= ~flag;
364	mutex_unlock(&chg->statlock);
365
366	dev_dbg(chg->dev, "status = %03lx\n", chg->status);
367}
368
369static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
370{
371	struct smbb_charger *chg = _data;
372
373	smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID);
374	power_supply_changed(chg->usb_psy);
375
376	return IRQ_HANDLED;
377}
378
379static irqreturn_t smbb_dc_valid_handler(int irq, void *_data)
380{
381	struct smbb_charger *chg = _data;
382
383	smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID);
384	if (!chg->dc_disabled)
385		power_supply_changed(chg->dc_psy);
386
387	return IRQ_HANDLED;
388}
389
390static irqreturn_t smbb_bat_temp_handler(int irq, void *_data)
391{
392	struct smbb_charger *chg = _data;
393	unsigned int val;
394	int rc;
395
396	rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val);
397	if (rc)
398		return IRQ_HANDLED;
399
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;
407	}
408	mutex_unlock(&chg->statlock);
409
410	power_supply_changed(chg->bat_psy);
411	return IRQ_HANDLED;
412}
413
414static irqreturn_t smbb_bat_present_handler(int irq, void *_data)
415{
416	struct smbb_charger *chg = _data;
417
418	smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT);
419	power_supply_changed(chg->bat_psy);
420
421	return IRQ_HANDLED;
422}
423
424static irqreturn_t smbb_chg_done_handler(int irq, void *_data)
425{
426	struct smbb_charger *chg = _data;
427
428	smbb_set_line_flag(chg, irq, STATUS_CHG_DONE);
429	power_supply_changed(chg->bat_psy);
430
431	return IRQ_HANDLED;
432}
433
434static irqreturn_t smbb_chg_gone_handler(int irq, void *_data)
435{
436	struct smbb_charger *chg = _data;
437
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);
443
444	return IRQ_HANDLED;
445}
446
447static irqreturn_t smbb_chg_fast_handler(int irq, void *_data)
448{
449	struct smbb_charger *chg = _data;
450
451	smbb_set_line_flag(chg, irq, STATUS_CHG_FAST);
452	power_supply_changed(chg->bat_psy);
453
454	return IRQ_HANDLED;
455}
456
457static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data)
458{
459	struct smbb_charger *chg = _data;
460
461	smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL);
462	power_supply_changed(chg->bat_psy);
463
464	return IRQ_HANDLED;
465}
466
467static 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 },
479};
480
481static int smbb_usbin_get_property(struct power_supply *psy,
482		enum power_supply_property psp,
483		union power_supply_propval *val)
484{
485	struct smbb_charger *chg = power_supply_get_drvdata(psy);
486	int rc = 0;
487
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;
504	}
505
506	return rc;
507}
508
509static int smbb_usbin_set_property(struct power_supply *psy,
510		enum power_supply_property psp,
511		const union power_supply_propval *val)
512{
513	struct smbb_charger *chg = power_supply_get_drvdata(psy);
514	int rc;
515
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;
524	}
525
526	return rc;
527}
528
529static int smbb_dcin_get_property(struct power_supply *psy,
530		enum power_supply_property psp,
531		union power_supply_propval *val)
532{
533	struct smbb_charger *chg = power_supply_get_drvdata(psy);
534	int rc = 0;
535
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;
552	}
553
554	return rc;
555}
556
557static int smbb_dcin_set_property(struct power_supply *psy,
558		enum power_supply_property psp,
559		const union power_supply_propval *val)
560{
561	struct smbb_charger *chg = power_supply_get_drvdata(psy);
562	int rc;
563
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;
572	}
573
574	return rc;
575}
576
577static int smbb_charger_writable_property(struct power_supply *psy,
578		enum power_supply_property psp)
579{
580	return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
581}
582
583static int smbb_battery_get_property(struct power_supply *psy,
584		enum power_supply_property psp,
585		union power_supply_propval *val)
586{
587	struct smbb_charger *chg = power_supply_get_drvdata(psy);
588	unsigned long status;
589	int rc = 0;
590
591	mutex_lock(&chg->statlock);
592	status = chg->status;
593	mutex_unlock(&chg->statlock);
594
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.
639		*/
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;
648	}
649
650	return rc;
651}
652
653static int smbb_battery_set_property(struct power_supply *psy,
654		enum power_supply_property psp,
655		const union power_supply_propval *val)
656{
657	struct smbb_charger *chg = power_supply_get_drvdata(psy);
658	int rc;
659
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;
670	}
671
672	return rc;
673}
674
675static int smbb_battery_writable_property(struct power_supply *psy,
676		enum power_supply_property psp)
677{
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;
684	}
685}
686
687static 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,
691};
692
693static 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,
702};
703
704static 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 },
712
713	/* Disable software timer */
714	{ SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
715
716	/* Clear and disable watchdog */
717	{ SMBB_CHG_WDOG_TIME, 0xff, 160 },
718	{ SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
719
720	/* Use charger based EoC detection */
721	{ SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
722
723	/* Disable GSM PA load adjustment.
724	* The PA signal is incorrectly connected on v2.
725	*/
726	{ SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
727
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 },
730
731	/* Enable battery temperature comparators */
732	{ SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
733
734	/* Stop USB enumeration timer */
735	{ SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
736
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
741
742	/* Stop USB enumeration timer, again */
743	{ SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
744
745	/* Enable charging */
746	{ SMBB_CHG_CTRL, CTRL_EN, CTRL_EN },
747};
748
749static char *smbb_bif[] = { "smbb-bif" };
750
751static 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,
759};
760
761static 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,
769};
770
771static 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,
779};
780
781static int smbb_charger_probe(struct platform_device *pdev)
782{
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;
788
789	chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
790	if (!chg)
791		return -ENOMEM;
792
793	chg->dev = &pdev->dev;
794	mutex_init(&chg->statlock);
795
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;
800	}
801
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;
806	}
807
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;
812	}
813
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;
818	}
819	dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
820
821	chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
822
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;
828		}
829	}
830
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);
839	}
840
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);
850	}
851
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);
862		}
863	}
864
865	for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
866		int irq;
867
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;
873		}
874
875		smbb_charger_irqs[i].handler(irq, chg);
876
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;
884		}
885	}
886
887	chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
888			"qcom,jeita-extended-temp-range");
889
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;
901	}
902
903	for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
904		const struct reg_off_mask_default *r = &smbb_charger_setup[i];
905
906		if (r->rev_mask & BIT(chg->revision))
907			continue;
908
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;
915		}
916	}
917
918	platform_set_drvdata(pdev, chg);
919
920	return 0;
921}
922
923static int smbb_charger_remove(struct platform_device *pdev)
924{
925	struct smbb_charger *chg;
926
927	chg = platform_get_drvdata(pdev);
928
929	regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
930
931	return 0;
932}
933
934static const struct of_device_id smbb_charger_id_table[] = {
935	{ .compatible = "qcom,pm8941-charger" },
936	{ }
937};
938MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
939
940static 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,
946	},
947};
948module_platform_driver(smbb_charger_driver);
949
950MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
951MODULE_LICENSE("GPL v2");
952