xref: /openbmc/linux/drivers/power/supply/max77693_charger.c (revision 8c0984e5a75337df513047ec92a6c09d78e3e5cd)
1*8c0984e5SSebastian Reichel /*
2*8c0984e5SSebastian Reichel  * max77693_charger.c - Battery charger driver for the Maxim 77693
3*8c0984e5SSebastian Reichel  *
4*8c0984e5SSebastian Reichel  * Copyright (C) 2014 Samsung Electronics
5*8c0984e5SSebastian Reichel  * Krzysztof Kozlowski <k.kozlowski@samsung.com>
6*8c0984e5SSebastian Reichel  *
7*8c0984e5SSebastian Reichel  * This program is free software; you can redistribute it and/or modify
8*8c0984e5SSebastian Reichel  * it under the terms of the GNU General Public License as published by
9*8c0984e5SSebastian Reichel  * the Free Software Foundation; either version 2 of the License, or
10*8c0984e5SSebastian Reichel  * (at your option) any later version.
11*8c0984e5SSebastian Reichel  *
12*8c0984e5SSebastian Reichel  * This program is distributed in the hope that it will be useful,
13*8c0984e5SSebastian Reichel  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*8c0984e5SSebastian Reichel  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*8c0984e5SSebastian Reichel  * GNU General Public License for more details.
16*8c0984e5SSebastian Reichel  */
17*8c0984e5SSebastian Reichel 
18*8c0984e5SSebastian Reichel #include <linux/module.h>
19*8c0984e5SSebastian Reichel #include <linux/platform_device.h>
20*8c0984e5SSebastian Reichel #include <linux/power_supply.h>
21*8c0984e5SSebastian Reichel #include <linux/regmap.h>
22*8c0984e5SSebastian Reichel #include <linux/mfd/max77693.h>
23*8c0984e5SSebastian Reichel #include <linux/mfd/max77693-common.h>
24*8c0984e5SSebastian Reichel #include <linux/mfd/max77693-private.h>
25*8c0984e5SSebastian Reichel 
26*8c0984e5SSebastian Reichel #define MAX77693_CHARGER_NAME				"max77693-charger"
27*8c0984e5SSebastian Reichel static const char *max77693_charger_model		= "MAX77693";
28*8c0984e5SSebastian Reichel static const char *max77693_charger_manufacturer	= "Maxim Integrated";
29*8c0984e5SSebastian Reichel 
30*8c0984e5SSebastian Reichel struct max77693_charger {
31*8c0984e5SSebastian Reichel 	struct device		*dev;
32*8c0984e5SSebastian Reichel 	struct max77693_dev	*max77693;
33*8c0984e5SSebastian Reichel 	struct power_supply	*charger;
34*8c0984e5SSebastian Reichel 
35*8c0984e5SSebastian Reichel 	u32 constant_volt;
36*8c0984e5SSebastian Reichel 	u32 min_system_volt;
37*8c0984e5SSebastian Reichel 	u32 thermal_regulation_temp;
38*8c0984e5SSebastian Reichel 	u32 batttery_overcurrent;
39*8c0984e5SSebastian Reichel 	u32 charge_input_threshold_volt;
40*8c0984e5SSebastian Reichel };
41*8c0984e5SSebastian Reichel 
42*8c0984e5SSebastian Reichel static int max77693_get_charger_state(struct regmap *regmap, int *val)
43*8c0984e5SSebastian Reichel {
44*8c0984e5SSebastian Reichel 	int ret;
45*8c0984e5SSebastian Reichel 	unsigned int data;
46*8c0984e5SSebastian Reichel 
47*8c0984e5SSebastian Reichel 	ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data);
48*8c0984e5SSebastian Reichel 	if (ret < 0)
49*8c0984e5SSebastian Reichel 		return ret;
50*8c0984e5SSebastian Reichel 
51*8c0984e5SSebastian Reichel 	data &= CHG_DETAILS_01_CHG_MASK;
52*8c0984e5SSebastian Reichel 	data >>= CHG_DETAILS_01_CHG_SHIFT;
53*8c0984e5SSebastian Reichel 
54*8c0984e5SSebastian Reichel 	switch (data) {
55*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_PREQUALIFICATION:
56*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_FAST_CONST_CURRENT:
57*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_FAST_CONST_VOLTAGE:
58*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_TOP_OFF:
59*8c0984e5SSebastian Reichel 	/* In high temp the charging current is reduced, but still charging */
60*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_HIGH_TEMP:
61*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_STATUS_CHARGING;
62*8c0984e5SSebastian Reichel 		break;
63*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_DONE:
64*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_STATUS_FULL;
65*8c0984e5SSebastian Reichel 		break;
66*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_TIMER_EXPIRED:
67*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_THERMISTOR_SUSPEND:
68*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
69*8c0984e5SSebastian Reichel 		break;
70*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_OFF:
71*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_OVER_TEMP:
72*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_WATCHDOG_EXPIRED:
73*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_STATUS_DISCHARGING;
74*8c0984e5SSebastian Reichel 		break;
75*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_RESERVED:
76*8c0984e5SSebastian Reichel 	default:
77*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_STATUS_UNKNOWN;
78*8c0984e5SSebastian Reichel 	}
79*8c0984e5SSebastian Reichel 
80*8c0984e5SSebastian Reichel 	return 0;
81*8c0984e5SSebastian Reichel }
82*8c0984e5SSebastian Reichel 
83*8c0984e5SSebastian Reichel static int max77693_get_charge_type(struct regmap *regmap, int *val)
84*8c0984e5SSebastian Reichel {
85*8c0984e5SSebastian Reichel 	int ret;
86*8c0984e5SSebastian Reichel 	unsigned int data;
87*8c0984e5SSebastian Reichel 
88*8c0984e5SSebastian Reichel 	ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data);
89*8c0984e5SSebastian Reichel 	if (ret < 0)
90*8c0984e5SSebastian Reichel 		return ret;
91*8c0984e5SSebastian Reichel 
92*8c0984e5SSebastian Reichel 	data &= CHG_DETAILS_01_CHG_MASK;
93*8c0984e5SSebastian Reichel 	data >>= CHG_DETAILS_01_CHG_SHIFT;
94*8c0984e5SSebastian Reichel 
95*8c0984e5SSebastian Reichel 	switch (data) {
96*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_PREQUALIFICATION:
97*8c0984e5SSebastian Reichel 	/*
98*8c0984e5SSebastian Reichel 	 * Top-off: trickle or fast? In top-off the current varies between
99*8c0984e5SSebastian Reichel 	 * 100 and 250 mA. It is higher than prequalification current.
100*8c0984e5SSebastian Reichel 	 */
101*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_TOP_OFF:
102*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
103*8c0984e5SSebastian Reichel 		break;
104*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_FAST_CONST_CURRENT:
105*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_FAST_CONST_VOLTAGE:
106*8c0984e5SSebastian Reichel 	/* In high temp the charging current is reduced, but still charging */
107*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_HIGH_TEMP:
108*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_CHARGE_TYPE_FAST;
109*8c0984e5SSebastian Reichel 		break;
110*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_DONE:
111*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_TIMER_EXPIRED:
112*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_THERMISTOR_SUSPEND:
113*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_OFF:
114*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_OVER_TEMP:
115*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_WATCHDOG_EXPIRED:
116*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
117*8c0984e5SSebastian Reichel 		break;
118*8c0984e5SSebastian Reichel 	case MAX77693_CHARGING_RESERVED:
119*8c0984e5SSebastian Reichel 	default:
120*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
121*8c0984e5SSebastian Reichel 	}
122*8c0984e5SSebastian Reichel 
123*8c0984e5SSebastian Reichel 	return 0;
124*8c0984e5SSebastian Reichel }
125*8c0984e5SSebastian Reichel 
126*8c0984e5SSebastian Reichel /*
127*8c0984e5SSebastian Reichel  * Supported health statuses:
128*8c0984e5SSebastian Reichel  *  - POWER_SUPPLY_HEALTH_DEAD
129*8c0984e5SSebastian Reichel  *  - POWER_SUPPLY_HEALTH_GOOD
130*8c0984e5SSebastian Reichel  *  - POWER_SUPPLY_HEALTH_OVERVOLTAGE
131*8c0984e5SSebastian Reichel  *  - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE
132*8c0984e5SSebastian Reichel  *  - POWER_SUPPLY_HEALTH_UNKNOWN
133*8c0984e5SSebastian Reichel  *  - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
134*8c0984e5SSebastian Reichel  */
135*8c0984e5SSebastian Reichel static int max77693_get_battery_health(struct regmap *regmap, int *val)
136*8c0984e5SSebastian Reichel {
137*8c0984e5SSebastian Reichel 	int ret;
138*8c0984e5SSebastian Reichel 	unsigned int data;
139*8c0984e5SSebastian Reichel 
140*8c0984e5SSebastian Reichel 	ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data);
141*8c0984e5SSebastian Reichel 	if (ret < 0)
142*8c0984e5SSebastian Reichel 		return ret;
143*8c0984e5SSebastian Reichel 
144*8c0984e5SSebastian Reichel 	data &= CHG_DETAILS_01_BAT_MASK;
145*8c0984e5SSebastian Reichel 	data >>= CHG_DETAILS_01_BAT_SHIFT;
146*8c0984e5SSebastian Reichel 
147*8c0984e5SSebastian Reichel 	switch (data) {
148*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_NOBAT:
149*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_HEALTH_DEAD;
150*8c0984e5SSebastian Reichel 		break;
151*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_PREQUALIFICATION:
152*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_GOOD:
153*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_LOWVOLTAGE:
154*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_HEALTH_GOOD;
155*8c0984e5SSebastian Reichel 		break;
156*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_TIMER_EXPIRED:
157*8c0984e5SSebastian Reichel 		/*
158*8c0984e5SSebastian Reichel 		 * Took longer to charge than expected, charging suspended.
159*8c0984e5SSebastian Reichel 		 * Damaged battery?
160*8c0984e5SSebastian Reichel 		 */
161*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
162*8c0984e5SSebastian Reichel 		break;
163*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_OVERVOLTAGE:
164*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
165*8c0984e5SSebastian Reichel 		break;
166*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_OVERCURRENT:
167*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
168*8c0984e5SSebastian Reichel 		break;
169*8c0984e5SSebastian Reichel 	case MAX77693_BATTERY_RESERVED:
170*8c0984e5SSebastian Reichel 	default:
171*8c0984e5SSebastian Reichel 		*val = POWER_SUPPLY_HEALTH_UNKNOWN;
172*8c0984e5SSebastian Reichel 		break;
173*8c0984e5SSebastian Reichel 	}
174*8c0984e5SSebastian Reichel 
175*8c0984e5SSebastian Reichel 	return 0;
176*8c0984e5SSebastian Reichel }
177*8c0984e5SSebastian Reichel 
178*8c0984e5SSebastian Reichel static int max77693_get_present(struct regmap *regmap, int *val)
179*8c0984e5SSebastian Reichel {
180*8c0984e5SSebastian Reichel 	unsigned int data;
181*8c0984e5SSebastian Reichel 	int ret;
182*8c0984e5SSebastian Reichel 
183*8c0984e5SSebastian Reichel 	/*
184*8c0984e5SSebastian Reichel 	 * Read CHG_INT_OK register. High DETBAT bit here should be
185*8c0984e5SSebastian Reichel 	 * equal to value 0x0 in CHG_DETAILS_01/BAT field.
186*8c0984e5SSebastian Reichel 	 */
187*8c0984e5SSebastian Reichel 	ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data);
188*8c0984e5SSebastian Reichel 	if (ret < 0)
189*8c0984e5SSebastian Reichel 		return ret;
190*8c0984e5SSebastian Reichel 
191*8c0984e5SSebastian Reichel 	*val = (data & CHG_INT_OK_DETBAT_MASK) ? 0 : 1;
192*8c0984e5SSebastian Reichel 
193*8c0984e5SSebastian Reichel 	return 0;
194*8c0984e5SSebastian Reichel }
195*8c0984e5SSebastian Reichel 
196*8c0984e5SSebastian Reichel static int max77693_get_online(struct regmap *regmap, int *val)
197*8c0984e5SSebastian Reichel {
198*8c0984e5SSebastian Reichel 	unsigned int data;
199*8c0984e5SSebastian Reichel 	int ret;
200*8c0984e5SSebastian Reichel 
201*8c0984e5SSebastian Reichel 	ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data);
202*8c0984e5SSebastian Reichel 	if (ret < 0)
203*8c0984e5SSebastian Reichel 		return ret;
204*8c0984e5SSebastian Reichel 
205*8c0984e5SSebastian Reichel 	*val = (data & CHG_INT_OK_CHGIN_MASK) ? 1 : 0;
206*8c0984e5SSebastian Reichel 
207*8c0984e5SSebastian Reichel 	return 0;
208*8c0984e5SSebastian Reichel }
209*8c0984e5SSebastian Reichel 
210*8c0984e5SSebastian Reichel static enum power_supply_property max77693_charger_props[] = {
211*8c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
212*8c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TYPE,
213*8c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
214*8c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_PRESENT,
215*8c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
216*8c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MODEL_NAME,
217*8c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
218*8c0984e5SSebastian Reichel };
219*8c0984e5SSebastian Reichel 
220*8c0984e5SSebastian Reichel static int max77693_charger_get_property(struct power_supply *psy,
221*8c0984e5SSebastian Reichel 			    enum power_supply_property psp,
222*8c0984e5SSebastian Reichel 			    union power_supply_propval *val)
223*8c0984e5SSebastian Reichel {
224*8c0984e5SSebastian Reichel 	struct max77693_charger *chg = power_supply_get_drvdata(psy);
225*8c0984e5SSebastian Reichel 	struct regmap *regmap = chg->max77693->regmap;
226*8c0984e5SSebastian Reichel 	int ret = 0;
227*8c0984e5SSebastian Reichel 
228*8c0984e5SSebastian Reichel 	switch (psp) {
229*8c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
230*8c0984e5SSebastian Reichel 		ret = max77693_get_charger_state(regmap, &val->intval);
231*8c0984e5SSebastian Reichel 		break;
232*8c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
233*8c0984e5SSebastian Reichel 		ret = max77693_get_charge_type(regmap, &val->intval);
234*8c0984e5SSebastian Reichel 		break;
235*8c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
236*8c0984e5SSebastian Reichel 		ret = max77693_get_battery_health(regmap, &val->intval);
237*8c0984e5SSebastian Reichel 		break;
238*8c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_PRESENT:
239*8c0984e5SSebastian Reichel 		ret = max77693_get_present(regmap, &val->intval);
240*8c0984e5SSebastian Reichel 		break;
241*8c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
242*8c0984e5SSebastian Reichel 		ret = max77693_get_online(regmap, &val->intval);
243*8c0984e5SSebastian Reichel 		break;
244*8c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MODEL_NAME:
245*8c0984e5SSebastian Reichel 		val->strval = max77693_charger_model;
246*8c0984e5SSebastian Reichel 		break;
247*8c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
248*8c0984e5SSebastian Reichel 		val->strval = max77693_charger_manufacturer;
249*8c0984e5SSebastian Reichel 		break;
250*8c0984e5SSebastian Reichel 	default:
251*8c0984e5SSebastian Reichel 		return -EINVAL;
252*8c0984e5SSebastian Reichel 	}
253*8c0984e5SSebastian Reichel 
254*8c0984e5SSebastian Reichel 	return ret;
255*8c0984e5SSebastian Reichel }
256*8c0984e5SSebastian Reichel 
257*8c0984e5SSebastian Reichel static const struct power_supply_desc max77693_charger_desc = {
258*8c0984e5SSebastian Reichel 	.name		= MAX77693_CHARGER_NAME,
259*8c0984e5SSebastian Reichel 	.type		= POWER_SUPPLY_TYPE_BATTERY,
260*8c0984e5SSebastian Reichel 	.properties	= max77693_charger_props,
261*8c0984e5SSebastian Reichel 	.num_properties	= ARRAY_SIZE(max77693_charger_props),
262*8c0984e5SSebastian Reichel 	.get_property	= max77693_charger_get_property,
263*8c0984e5SSebastian Reichel };
264*8c0984e5SSebastian Reichel 
265*8c0984e5SSebastian Reichel static ssize_t device_attr_store(struct device *dev,
266*8c0984e5SSebastian Reichel 		struct device_attribute *attr, const char *buf, size_t count,
267*8c0984e5SSebastian Reichel 		int (*fn)(struct max77693_charger *, unsigned long))
268*8c0984e5SSebastian Reichel {
269*8c0984e5SSebastian Reichel 	struct max77693_charger *chg = dev_get_drvdata(dev);
270*8c0984e5SSebastian Reichel 	unsigned long val;
271*8c0984e5SSebastian Reichel 	int ret;
272*8c0984e5SSebastian Reichel 
273*8c0984e5SSebastian Reichel 	ret = kstrtoul(buf, 10, &val);
274*8c0984e5SSebastian Reichel 	if (ret)
275*8c0984e5SSebastian Reichel 		return ret;
276*8c0984e5SSebastian Reichel 
277*8c0984e5SSebastian Reichel 	ret = fn(chg, val);
278*8c0984e5SSebastian Reichel 	if (ret)
279*8c0984e5SSebastian Reichel 		return ret;
280*8c0984e5SSebastian Reichel 
281*8c0984e5SSebastian Reichel 	return count;
282*8c0984e5SSebastian Reichel }
283*8c0984e5SSebastian Reichel 
284*8c0984e5SSebastian Reichel static ssize_t fast_charge_timer_show(struct device *dev,
285*8c0984e5SSebastian Reichel 		struct device_attribute *attr, char *buf)
286*8c0984e5SSebastian Reichel {
287*8c0984e5SSebastian Reichel 	struct max77693_charger *chg = dev_get_drvdata(dev);
288*8c0984e5SSebastian Reichel 	unsigned int data, val;
289*8c0984e5SSebastian Reichel 	int ret;
290*8c0984e5SSebastian Reichel 
291*8c0984e5SSebastian Reichel 	ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_01,
292*8c0984e5SSebastian Reichel 			&data);
293*8c0984e5SSebastian Reichel 	if (ret < 0)
294*8c0984e5SSebastian Reichel 		return ret;
295*8c0984e5SSebastian Reichel 
296*8c0984e5SSebastian Reichel 	data &= CHG_CNFG_01_FCHGTIME_MASK;
297*8c0984e5SSebastian Reichel 	data >>= CHG_CNFG_01_FCHGTIME_SHIFT;
298*8c0984e5SSebastian Reichel 	switch (data) {
299*8c0984e5SSebastian Reichel 	case 0x1 ... 0x7:
300*8c0984e5SSebastian Reichel 		/* Starting from 4 hours, step by 2 hours */
301*8c0984e5SSebastian Reichel 		val = 4 + (data - 1) * 2;
302*8c0984e5SSebastian Reichel 		break;
303*8c0984e5SSebastian Reichel 	case 0x0:
304*8c0984e5SSebastian Reichel 	default:
305*8c0984e5SSebastian Reichel 		val = 0;
306*8c0984e5SSebastian Reichel 		break;
307*8c0984e5SSebastian Reichel 	}
308*8c0984e5SSebastian Reichel 
309*8c0984e5SSebastian Reichel 	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
310*8c0984e5SSebastian Reichel }
311*8c0984e5SSebastian Reichel 
312*8c0984e5SSebastian Reichel static int max77693_set_fast_charge_timer(struct max77693_charger *chg,
313*8c0984e5SSebastian Reichel 		unsigned long hours)
314*8c0984e5SSebastian Reichel {
315*8c0984e5SSebastian Reichel 	unsigned int data;
316*8c0984e5SSebastian Reichel 
317*8c0984e5SSebastian Reichel 	/*
318*8c0984e5SSebastian Reichel 	 * 0x00 - disable
319*8c0984e5SSebastian Reichel 	 * 0x01 - 4h
320*8c0984e5SSebastian Reichel 	 * 0x02 - 6h
321*8c0984e5SSebastian Reichel 	 * ...
322*8c0984e5SSebastian Reichel 	 * 0x07 - 16h
323*8c0984e5SSebastian Reichel 	 * Round down odd values.
324*8c0984e5SSebastian Reichel 	 */
325*8c0984e5SSebastian Reichel 	switch (hours) {
326*8c0984e5SSebastian Reichel 	case 4 ... 16:
327*8c0984e5SSebastian Reichel 		data = (hours - 4) / 2 + 1;
328*8c0984e5SSebastian Reichel 		break;
329*8c0984e5SSebastian Reichel 	case 0:
330*8c0984e5SSebastian Reichel 		/* Disable */
331*8c0984e5SSebastian Reichel 		data = 0;
332*8c0984e5SSebastian Reichel 		break;
333*8c0984e5SSebastian Reichel 	default:
334*8c0984e5SSebastian Reichel 		return -EINVAL;
335*8c0984e5SSebastian Reichel 	}
336*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_01_FCHGTIME_SHIFT;
337*8c0984e5SSebastian Reichel 
338*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
339*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_01,
340*8c0984e5SSebastian Reichel 			CHG_CNFG_01_FCHGTIME_MASK, data);
341*8c0984e5SSebastian Reichel }
342*8c0984e5SSebastian Reichel 
343*8c0984e5SSebastian Reichel static ssize_t fast_charge_timer_store(struct device *dev,
344*8c0984e5SSebastian Reichel 		struct device_attribute *attr, const char *buf, size_t count)
345*8c0984e5SSebastian Reichel {
346*8c0984e5SSebastian Reichel 	return device_attr_store(dev, attr, buf, count,
347*8c0984e5SSebastian Reichel 			max77693_set_fast_charge_timer);
348*8c0984e5SSebastian Reichel }
349*8c0984e5SSebastian Reichel 
350*8c0984e5SSebastian Reichel static ssize_t top_off_threshold_current_show(struct device *dev,
351*8c0984e5SSebastian Reichel 		struct device_attribute *attr, char *buf)
352*8c0984e5SSebastian Reichel {
353*8c0984e5SSebastian Reichel 	struct max77693_charger *chg = dev_get_drvdata(dev);
354*8c0984e5SSebastian Reichel 	unsigned int data, val;
355*8c0984e5SSebastian Reichel 	int ret;
356*8c0984e5SSebastian Reichel 
357*8c0984e5SSebastian Reichel 	ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03,
358*8c0984e5SSebastian Reichel 			&data);
359*8c0984e5SSebastian Reichel 	if (ret < 0)
360*8c0984e5SSebastian Reichel 		return ret;
361*8c0984e5SSebastian Reichel 
362*8c0984e5SSebastian Reichel 	data &= CHG_CNFG_03_TOITH_MASK;
363*8c0984e5SSebastian Reichel 	data >>= CHG_CNFG_03_TOITH_SHIFT;
364*8c0984e5SSebastian Reichel 
365*8c0984e5SSebastian Reichel 	if (data <= 0x04)
366*8c0984e5SSebastian Reichel 		val = 100000 + data * 25000;
367*8c0984e5SSebastian Reichel 	else
368*8c0984e5SSebastian Reichel 		val = data * 50000;
369*8c0984e5SSebastian Reichel 
370*8c0984e5SSebastian Reichel 	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
371*8c0984e5SSebastian Reichel }
372*8c0984e5SSebastian Reichel 
373*8c0984e5SSebastian Reichel static int max77693_set_top_off_threshold_current(struct max77693_charger *chg,
374*8c0984e5SSebastian Reichel 		unsigned long uamp)
375*8c0984e5SSebastian Reichel {
376*8c0984e5SSebastian Reichel 	unsigned int data;
377*8c0984e5SSebastian Reichel 
378*8c0984e5SSebastian Reichel 	if (uamp < 100000 || uamp > 350000)
379*8c0984e5SSebastian Reichel 		return -EINVAL;
380*8c0984e5SSebastian Reichel 
381*8c0984e5SSebastian Reichel 	if (uamp <= 200000)
382*8c0984e5SSebastian Reichel 		data = (uamp - 100000) / 25000;
383*8c0984e5SSebastian Reichel 	else
384*8c0984e5SSebastian Reichel 		/* (200000, 350000> */
385*8c0984e5SSebastian Reichel 		data = uamp / 50000;
386*8c0984e5SSebastian Reichel 
387*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_03_TOITH_SHIFT;
388*8c0984e5SSebastian Reichel 
389*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
390*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_03,
391*8c0984e5SSebastian Reichel 			CHG_CNFG_03_TOITH_MASK, data);
392*8c0984e5SSebastian Reichel }
393*8c0984e5SSebastian Reichel 
394*8c0984e5SSebastian Reichel static ssize_t top_off_threshold_current_store(struct device *dev,
395*8c0984e5SSebastian Reichel 		struct device_attribute *attr, const char *buf, size_t count)
396*8c0984e5SSebastian Reichel {
397*8c0984e5SSebastian Reichel 	return device_attr_store(dev, attr, buf, count,
398*8c0984e5SSebastian Reichel 			max77693_set_top_off_threshold_current);
399*8c0984e5SSebastian Reichel }
400*8c0984e5SSebastian Reichel 
401*8c0984e5SSebastian Reichel static ssize_t top_off_timer_show(struct device *dev,
402*8c0984e5SSebastian Reichel 		struct device_attribute *attr, char *buf)
403*8c0984e5SSebastian Reichel {
404*8c0984e5SSebastian Reichel 	struct max77693_charger *chg = dev_get_drvdata(dev);
405*8c0984e5SSebastian Reichel 	unsigned int data, val;
406*8c0984e5SSebastian Reichel 	int ret;
407*8c0984e5SSebastian Reichel 
408*8c0984e5SSebastian Reichel 	ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03,
409*8c0984e5SSebastian Reichel 			&data);
410*8c0984e5SSebastian Reichel 	if (ret < 0)
411*8c0984e5SSebastian Reichel 		return ret;
412*8c0984e5SSebastian Reichel 
413*8c0984e5SSebastian Reichel 	data &= CHG_CNFG_03_TOTIME_MASK;
414*8c0984e5SSebastian Reichel 	data >>= CHG_CNFG_03_TOTIME_SHIFT;
415*8c0984e5SSebastian Reichel 
416*8c0984e5SSebastian Reichel 	val = data * 10;
417*8c0984e5SSebastian Reichel 
418*8c0984e5SSebastian Reichel 	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
419*8c0984e5SSebastian Reichel }
420*8c0984e5SSebastian Reichel 
421*8c0984e5SSebastian Reichel static int max77693_set_top_off_timer(struct max77693_charger *chg,
422*8c0984e5SSebastian Reichel 		unsigned long minutes)
423*8c0984e5SSebastian Reichel {
424*8c0984e5SSebastian Reichel 	unsigned int data;
425*8c0984e5SSebastian Reichel 
426*8c0984e5SSebastian Reichel 	if (minutes > 70)
427*8c0984e5SSebastian Reichel 		return -EINVAL;
428*8c0984e5SSebastian Reichel 
429*8c0984e5SSebastian Reichel 	data = minutes / 10;
430*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_03_TOTIME_SHIFT;
431*8c0984e5SSebastian Reichel 
432*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
433*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_03,
434*8c0984e5SSebastian Reichel 			CHG_CNFG_03_TOTIME_MASK, data);
435*8c0984e5SSebastian Reichel }
436*8c0984e5SSebastian Reichel 
437*8c0984e5SSebastian Reichel static ssize_t top_off_timer_store(struct device *dev,
438*8c0984e5SSebastian Reichel 		struct device_attribute *attr, const char *buf, size_t count)
439*8c0984e5SSebastian Reichel {
440*8c0984e5SSebastian Reichel 	return device_attr_store(dev, attr, buf, count,
441*8c0984e5SSebastian Reichel 			max77693_set_top_off_timer);
442*8c0984e5SSebastian Reichel }
443*8c0984e5SSebastian Reichel 
444*8c0984e5SSebastian Reichel static DEVICE_ATTR_RW(fast_charge_timer);
445*8c0984e5SSebastian Reichel static DEVICE_ATTR_RW(top_off_threshold_current);
446*8c0984e5SSebastian Reichel static DEVICE_ATTR_RW(top_off_timer);
447*8c0984e5SSebastian Reichel 
448*8c0984e5SSebastian Reichel static int max77693_set_constant_volt(struct max77693_charger *chg,
449*8c0984e5SSebastian Reichel 		unsigned int uvolt)
450*8c0984e5SSebastian Reichel {
451*8c0984e5SSebastian Reichel 	unsigned int data;
452*8c0984e5SSebastian Reichel 
453*8c0984e5SSebastian Reichel 	/*
454*8c0984e5SSebastian Reichel 	 * 0x00 - 3.650 V
455*8c0984e5SSebastian Reichel 	 * 0x01 - 3.675 V
456*8c0984e5SSebastian Reichel 	 * ...
457*8c0984e5SSebastian Reichel 	 * 0x1b - 4.325 V
458*8c0984e5SSebastian Reichel 	 * 0x1c - 4.340 V
459*8c0984e5SSebastian Reichel 	 * 0x1d - 4.350 V
460*8c0984e5SSebastian Reichel 	 * 0x1e - 4.375 V
461*8c0984e5SSebastian Reichel 	 * 0x1f - 4.400 V
462*8c0984e5SSebastian Reichel 	 */
463*8c0984e5SSebastian Reichel 	if (uvolt >= 3650000 && uvolt < 4340000)
464*8c0984e5SSebastian Reichel 		data = (uvolt - 3650000) / 25000;
465*8c0984e5SSebastian Reichel 	else if (uvolt >= 4340000 && uvolt < 4350000)
466*8c0984e5SSebastian Reichel 		data = 0x1c;
467*8c0984e5SSebastian Reichel 	else if (uvolt >= 4350000 && uvolt <= 4400000)
468*8c0984e5SSebastian Reichel 		data = 0x1d + (uvolt - 4350000) / 25000;
469*8c0984e5SSebastian Reichel 	else {
470*8c0984e5SSebastian Reichel 		dev_err(chg->dev, "Wrong value for charging constant voltage\n");
471*8c0984e5SSebastian Reichel 		return -EINVAL;
472*8c0984e5SSebastian Reichel 	}
473*8c0984e5SSebastian Reichel 
474*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_04_CHGCVPRM_SHIFT;
475*8c0984e5SSebastian Reichel 
476*8c0984e5SSebastian Reichel 	dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt,
477*8c0984e5SSebastian Reichel 			data);
478*8c0984e5SSebastian Reichel 
479*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
480*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_04,
481*8c0984e5SSebastian Reichel 			CHG_CNFG_04_CHGCVPRM_MASK, data);
482*8c0984e5SSebastian Reichel }
483*8c0984e5SSebastian Reichel 
484*8c0984e5SSebastian Reichel static int max77693_set_min_system_volt(struct max77693_charger *chg,
485*8c0984e5SSebastian Reichel 		unsigned int uvolt)
486*8c0984e5SSebastian Reichel {
487*8c0984e5SSebastian Reichel 	unsigned int data;
488*8c0984e5SSebastian Reichel 
489*8c0984e5SSebastian Reichel 	if (uvolt < 3000000 || uvolt > 3700000) {
490*8c0984e5SSebastian Reichel 		dev_err(chg->dev, "Wrong value for minimum system regulation voltage\n");
491*8c0984e5SSebastian Reichel 		return -EINVAL;
492*8c0984e5SSebastian Reichel 	}
493*8c0984e5SSebastian Reichel 
494*8c0984e5SSebastian Reichel 	data = (uvolt - 3000000) / 100000;
495*8c0984e5SSebastian Reichel 
496*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_04_MINVSYS_SHIFT;
497*8c0984e5SSebastian Reichel 
498*8c0984e5SSebastian Reichel 	dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n",
499*8c0984e5SSebastian Reichel 			uvolt, data);
500*8c0984e5SSebastian Reichel 
501*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
502*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_04,
503*8c0984e5SSebastian Reichel 			CHG_CNFG_04_MINVSYS_MASK, data);
504*8c0984e5SSebastian Reichel }
505*8c0984e5SSebastian Reichel 
506*8c0984e5SSebastian Reichel static int max77693_set_thermal_regulation_temp(struct max77693_charger *chg,
507*8c0984e5SSebastian Reichel 		unsigned int cels)
508*8c0984e5SSebastian Reichel {
509*8c0984e5SSebastian Reichel 	unsigned int data;
510*8c0984e5SSebastian Reichel 
511*8c0984e5SSebastian Reichel 	switch (cels) {
512*8c0984e5SSebastian Reichel 	case 70:
513*8c0984e5SSebastian Reichel 	case 85:
514*8c0984e5SSebastian Reichel 	case 100:
515*8c0984e5SSebastian Reichel 	case 115:
516*8c0984e5SSebastian Reichel 		data = (cels - 70) / 15;
517*8c0984e5SSebastian Reichel 		break;
518*8c0984e5SSebastian Reichel 	default:
519*8c0984e5SSebastian Reichel 		dev_err(chg->dev, "Wrong value for thermal regulation loop temperature\n");
520*8c0984e5SSebastian Reichel 		return -EINVAL;
521*8c0984e5SSebastian Reichel 	}
522*8c0984e5SSebastian Reichel 
523*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_07_REGTEMP_SHIFT;
524*8c0984e5SSebastian Reichel 
525*8c0984e5SSebastian Reichel 	dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n",
526*8c0984e5SSebastian Reichel 			cels, data);
527*8c0984e5SSebastian Reichel 
528*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
529*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_07,
530*8c0984e5SSebastian Reichel 			CHG_CNFG_07_REGTEMP_MASK, data);
531*8c0984e5SSebastian Reichel }
532*8c0984e5SSebastian Reichel 
533*8c0984e5SSebastian Reichel static int max77693_set_batttery_overcurrent(struct max77693_charger *chg,
534*8c0984e5SSebastian Reichel 		unsigned int uamp)
535*8c0984e5SSebastian Reichel {
536*8c0984e5SSebastian Reichel 	unsigned int data;
537*8c0984e5SSebastian Reichel 
538*8c0984e5SSebastian Reichel 	if (uamp && (uamp < 2000000 || uamp > 3500000)) {
539*8c0984e5SSebastian Reichel 		dev_err(chg->dev, "Wrong value for battery overcurrent\n");
540*8c0984e5SSebastian Reichel 		return -EINVAL;
541*8c0984e5SSebastian Reichel 	}
542*8c0984e5SSebastian Reichel 
543*8c0984e5SSebastian Reichel 	if (uamp)
544*8c0984e5SSebastian Reichel 		data = ((uamp - 2000000) / 250000) + 1;
545*8c0984e5SSebastian Reichel 	else
546*8c0984e5SSebastian Reichel 		data = 0; /* disable */
547*8c0984e5SSebastian Reichel 
548*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_12_B2SOVRC_SHIFT;
549*8c0984e5SSebastian Reichel 
550*8c0984e5SSebastian Reichel 	dev_dbg(chg->dev, "Battery overcurrent: %u (0x%x)\n", uamp, data);
551*8c0984e5SSebastian Reichel 
552*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
553*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_12,
554*8c0984e5SSebastian Reichel 			CHG_CNFG_12_B2SOVRC_MASK, data);
555*8c0984e5SSebastian Reichel }
556*8c0984e5SSebastian Reichel 
557*8c0984e5SSebastian Reichel static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg,
558*8c0984e5SSebastian Reichel 		unsigned int uvolt)
559*8c0984e5SSebastian Reichel {
560*8c0984e5SSebastian Reichel 	unsigned int data;
561*8c0984e5SSebastian Reichel 
562*8c0984e5SSebastian Reichel 	switch (uvolt) {
563*8c0984e5SSebastian Reichel 	case 4300000:
564*8c0984e5SSebastian Reichel 		data = 0x0;
565*8c0984e5SSebastian Reichel 		break;
566*8c0984e5SSebastian Reichel 	case 4700000:
567*8c0984e5SSebastian Reichel 	case 4800000:
568*8c0984e5SSebastian Reichel 	case 4900000:
569*8c0984e5SSebastian Reichel 		data = (uvolt - 4700000) / 100000;
570*8c0984e5SSebastian Reichel 	default:
571*8c0984e5SSebastian Reichel 		dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n");
572*8c0984e5SSebastian Reichel 		return -EINVAL;
573*8c0984e5SSebastian Reichel 	}
574*8c0984e5SSebastian Reichel 
575*8c0984e5SSebastian Reichel 	data <<= CHG_CNFG_12_VCHGINREG_SHIFT;
576*8c0984e5SSebastian Reichel 
577*8c0984e5SSebastian Reichel 	dev_dbg(chg->dev, "Charge input voltage regulation threshold: %u (0x%x)\n",
578*8c0984e5SSebastian Reichel 			uvolt, data);
579*8c0984e5SSebastian Reichel 
580*8c0984e5SSebastian Reichel 	return regmap_update_bits(chg->max77693->regmap,
581*8c0984e5SSebastian Reichel 			MAX77693_CHG_REG_CHG_CNFG_12,
582*8c0984e5SSebastian Reichel 			CHG_CNFG_12_VCHGINREG_MASK, data);
583*8c0984e5SSebastian Reichel }
584*8c0984e5SSebastian Reichel 
585*8c0984e5SSebastian Reichel /*
586*8c0984e5SSebastian Reichel  * Sets charger registers to proper and safe default values.
587*8c0984e5SSebastian Reichel  */
588*8c0984e5SSebastian Reichel static int max77693_reg_init(struct max77693_charger *chg)
589*8c0984e5SSebastian Reichel {
590*8c0984e5SSebastian Reichel 	int ret;
591*8c0984e5SSebastian Reichel 	unsigned int data;
592*8c0984e5SSebastian Reichel 
593*8c0984e5SSebastian Reichel 	/* Unlock charger register protection */
594*8c0984e5SSebastian Reichel 	data = (0x3 << CHG_CNFG_06_CHGPROT_SHIFT);
595*8c0984e5SSebastian Reichel 	ret = regmap_update_bits(chg->max77693->regmap,
596*8c0984e5SSebastian Reichel 				MAX77693_CHG_REG_CHG_CNFG_06,
597*8c0984e5SSebastian Reichel 				CHG_CNFG_06_CHGPROT_MASK, data);
598*8c0984e5SSebastian Reichel 	if (ret) {
599*8c0984e5SSebastian Reichel 		dev_err(chg->dev, "Error unlocking registers: %d\n", ret);
600*8c0984e5SSebastian Reichel 		return ret;
601*8c0984e5SSebastian Reichel 	}
602*8c0984e5SSebastian Reichel 
603*8c0984e5SSebastian Reichel 	ret = max77693_set_fast_charge_timer(chg, DEFAULT_FAST_CHARGE_TIMER);
604*8c0984e5SSebastian Reichel 	if (ret)
605*8c0984e5SSebastian Reichel 		return ret;
606*8c0984e5SSebastian Reichel 
607*8c0984e5SSebastian Reichel 	ret = max77693_set_top_off_threshold_current(chg,
608*8c0984e5SSebastian Reichel 			DEFAULT_TOP_OFF_THRESHOLD_CURRENT);
609*8c0984e5SSebastian Reichel 	if (ret)
610*8c0984e5SSebastian Reichel 		return ret;
611*8c0984e5SSebastian Reichel 
612*8c0984e5SSebastian Reichel 	ret = max77693_set_top_off_timer(chg, DEFAULT_TOP_OFF_TIMER);
613*8c0984e5SSebastian Reichel 	if (ret)
614*8c0984e5SSebastian Reichel 		return ret;
615*8c0984e5SSebastian Reichel 
616*8c0984e5SSebastian Reichel 	ret = max77693_set_constant_volt(chg, chg->constant_volt);
617*8c0984e5SSebastian Reichel 	if (ret)
618*8c0984e5SSebastian Reichel 		return ret;
619*8c0984e5SSebastian Reichel 
620*8c0984e5SSebastian Reichel 	ret = max77693_set_min_system_volt(chg, chg->min_system_volt);
621*8c0984e5SSebastian Reichel 	if (ret)
622*8c0984e5SSebastian Reichel 		return ret;
623*8c0984e5SSebastian Reichel 
624*8c0984e5SSebastian Reichel 	ret = max77693_set_thermal_regulation_temp(chg,
625*8c0984e5SSebastian Reichel 			chg->thermal_regulation_temp);
626*8c0984e5SSebastian Reichel 	if (ret)
627*8c0984e5SSebastian Reichel 		return ret;
628*8c0984e5SSebastian Reichel 
629*8c0984e5SSebastian Reichel 	ret = max77693_set_batttery_overcurrent(chg, chg->batttery_overcurrent);
630*8c0984e5SSebastian Reichel 	if (ret)
631*8c0984e5SSebastian Reichel 		return ret;
632*8c0984e5SSebastian Reichel 
633*8c0984e5SSebastian Reichel 	return max77693_set_charge_input_threshold_volt(chg,
634*8c0984e5SSebastian Reichel 			chg->charge_input_threshold_volt);
635*8c0984e5SSebastian Reichel }
636*8c0984e5SSebastian Reichel 
637*8c0984e5SSebastian Reichel #ifdef CONFIG_OF
638*8c0984e5SSebastian Reichel static int max77693_dt_init(struct device *dev, struct max77693_charger *chg)
639*8c0984e5SSebastian Reichel {
640*8c0984e5SSebastian Reichel 	struct device_node *np = dev->of_node;
641*8c0984e5SSebastian Reichel 
642*8c0984e5SSebastian Reichel 	if (!np) {
643*8c0984e5SSebastian Reichel 		dev_err(dev, "no charger OF node\n");
644*8c0984e5SSebastian Reichel 		return -EINVAL;
645*8c0984e5SSebastian Reichel 	}
646*8c0984e5SSebastian Reichel 
647*8c0984e5SSebastian Reichel 	if (of_property_read_u32(np, "maxim,constant-microvolt",
648*8c0984e5SSebastian Reichel 			&chg->constant_volt))
649*8c0984e5SSebastian Reichel 		chg->constant_volt = DEFAULT_CONSTANT_VOLT;
650*8c0984e5SSebastian Reichel 
651*8c0984e5SSebastian Reichel 	if (of_property_read_u32(np, "maxim,min-system-microvolt",
652*8c0984e5SSebastian Reichel 			&chg->min_system_volt))
653*8c0984e5SSebastian Reichel 		chg->min_system_volt = DEFAULT_MIN_SYSTEM_VOLT;
654*8c0984e5SSebastian Reichel 
655*8c0984e5SSebastian Reichel 	if (of_property_read_u32(np, "maxim,thermal-regulation-celsius",
656*8c0984e5SSebastian Reichel 			&chg->thermal_regulation_temp))
657*8c0984e5SSebastian Reichel 		chg->thermal_regulation_temp = DEFAULT_THERMAL_REGULATION_TEMP;
658*8c0984e5SSebastian Reichel 
659*8c0984e5SSebastian Reichel 	if (of_property_read_u32(np, "maxim,battery-overcurrent-microamp",
660*8c0984e5SSebastian Reichel 			&chg->batttery_overcurrent))
661*8c0984e5SSebastian Reichel 		chg->batttery_overcurrent = DEFAULT_BATTERY_OVERCURRENT;
662*8c0984e5SSebastian Reichel 
663*8c0984e5SSebastian Reichel 	if (of_property_read_u32(np, "maxim,charge-input-threshold-microvolt",
664*8c0984e5SSebastian Reichel 			&chg->charge_input_threshold_volt))
665*8c0984e5SSebastian Reichel 		chg->charge_input_threshold_volt =
666*8c0984e5SSebastian Reichel 			DEFAULT_CHARGER_INPUT_THRESHOLD_VOLT;
667*8c0984e5SSebastian Reichel 
668*8c0984e5SSebastian Reichel 	return 0;
669*8c0984e5SSebastian Reichel }
670*8c0984e5SSebastian Reichel #else /* CONFIG_OF */
671*8c0984e5SSebastian Reichel static int max77693_dt_init(struct device *dev, struct max77693_charger *chg)
672*8c0984e5SSebastian Reichel {
673*8c0984e5SSebastian Reichel 	return 0;
674*8c0984e5SSebastian Reichel }
675*8c0984e5SSebastian Reichel #endif /* CONFIG_OF */
676*8c0984e5SSebastian Reichel 
677*8c0984e5SSebastian Reichel static int max77693_charger_probe(struct platform_device *pdev)
678*8c0984e5SSebastian Reichel {
679*8c0984e5SSebastian Reichel 	struct max77693_charger *chg;
680*8c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = {};
681*8c0984e5SSebastian Reichel 	struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
682*8c0984e5SSebastian Reichel 	int ret;
683*8c0984e5SSebastian Reichel 
684*8c0984e5SSebastian Reichel 	chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
685*8c0984e5SSebastian Reichel 	if (!chg)
686*8c0984e5SSebastian Reichel 		return -ENOMEM;
687*8c0984e5SSebastian Reichel 
688*8c0984e5SSebastian Reichel 	platform_set_drvdata(pdev, chg);
689*8c0984e5SSebastian Reichel 	chg->dev = &pdev->dev;
690*8c0984e5SSebastian Reichel 	chg->max77693 = max77693;
691*8c0984e5SSebastian Reichel 
692*8c0984e5SSebastian Reichel 	ret = max77693_dt_init(&pdev->dev, chg);
693*8c0984e5SSebastian Reichel 	if (ret)
694*8c0984e5SSebastian Reichel 		return ret;
695*8c0984e5SSebastian Reichel 
696*8c0984e5SSebastian Reichel 	ret = max77693_reg_init(chg);
697*8c0984e5SSebastian Reichel 	if (ret)
698*8c0984e5SSebastian Reichel 		return ret;
699*8c0984e5SSebastian Reichel 
700*8c0984e5SSebastian Reichel 	psy_cfg.drv_data = chg;
701*8c0984e5SSebastian Reichel 
702*8c0984e5SSebastian Reichel 	ret = device_create_file(&pdev->dev, &dev_attr_fast_charge_timer);
703*8c0984e5SSebastian Reichel 	if (ret) {
704*8c0984e5SSebastian Reichel 		dev_err(&pdev->dev, "failed: create fast charge timer sysfs entry\n");
705*8c0984e5SSebastian Reichel 		goto err;
706*8c0984e5SSebastian Reichel 	}
707*8c0984e5SSebastian Reichel 
708*8c0984e5SSebastian Reichel 	ret = device_create_file(&pdev->dev,
709*8c0984e5SSebastian Reichel 			&dev_attr_top_off_threshold_current);
710*8c0984e5SSebastian Reichel 	if (ret) {
711*8c0984e5SSebastian Reichel 		dev_err(&pdev->dev, "failed: create top off current sysfs entry\n");
712*8c0984e5SSebastian Reichel 		goto err;
713*8c0984e5SSebastian Reichel 	}
714*8c0984e5SSebastian Reichel 
715*8c0984e5SSebastian Reichel 	ret = device_create_file(&pdev->dev, &dev_attr_top_off_timer);
716*8c0984e5SSebastian Reichel 	if (ret) {
717*8c0984e5SSebastian Reichel 		dev_err(&pdev->dev, "failed: create top off timer sysfs entry\n");
718*8c0984e5SSebastian Reichel 		goto err;
719*8c0984e5SSebastian Reichel 	}
720*8c0984e5SSebastian Reichel 
721*8c0984e5SSebastian Reichel 	chg->charger = power_supply_register(&pdev->dev,
722*8c0984e5SSebastian Reichel 						&max77693_charger_desc,
723*8c0984e5SSebastian Reichel 						&psy_cfg);
724*8c0984e5SSebastian Reichel 	if (IS_ERR(chg->charger)) {
725*8c0984e5SSebastian Reichel 		dev_err(&pdev->dev, "failed: power supply register\n");
726*8c0984e5SSebastian Reichel 		ret = PTR_ERR(chg->charger);
727*8c0984e5SSebastian Reichel 		goto err;
728*8c0984e5SSebastian Reichel 	}
729*8c0984e5SSebastian Reichel 
730*8c0984e5SSebastian Reichel 	return 0;
731*8c0984e5SSebastian Reichel 
732*8c0984e5SSebastian Reichel err:
733*8c0984e5SSebastian Reichel 	device_remove_file(&pdev->dev, &dev_attr_top_off_timer);
734*8c0984e5SSebastian Reichel 	device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current);
735*8c0984e5SSebastian Reichel 	device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
736*8c0984e5SSebastian Reichel 
737*8c0984e5SSebastian Reichel 	return ret;
738*8c0984e5SSebastian Reichel }
739*8c0984e5SSebastian Reichel 
740*8c0984e5SSebastian Reichel static int max77693_charger_remove(struct platform_device *pdev)
741*8c0984e5SSebastian Reichel {
742*8c0984e5SSebastian Reichel 	struct max77693_charger *chg = platform_get_drvdata(pdev);
743*8c0984e5SSebastian Reichel 
744*8c0984e5SSebastian Reichel 	device_remove_file(&pdev->dev, &dev_attr_top_off_timer);
745*8c0984e5SSebastian Reichel 	device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current);
746*8c0984e5SSebastian Reichel 	device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
747*8c0984e5SSebastian Reichel 
748*8c0984e5SSebastian Reichel 	power_supply_unregister(chg->charger);
749*8c0984e5SSebastian Reichel 
750*8c0984e5SSebastian Reichel 	return 0;
751*8c0984e5SSebastian Reichel }
752*8c0984e5SSebastian Reichel 
753*8c0984e5SSebastian Reichel static const struct platform_device_id max77693_charger_id[] = {
754*8c0984e5SSebastian Reichel 	{ "max77693-charger", 0, },
755*8c0984e5SSebastian Reichel 	{ }
756*8c0984e5SSebastian Reichel };
757*8c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(platform, max77693_charger_id);
758*8c0984e5SSebastian Reichel 
759*8c0984e5SSebastian Reichel static struct platform_driver max77693_charger_driver = {
760*8c0984e5SSebastian Reichel 	.driver = {
761*8c0984e5SSebastian Reichel 		.name	= "max77693-charger",
762*8c0984e5SSebastian Reichel 	},
763*8c0984e5SSebastian Reichel 	.probe		= max77693_charger_probe,
764*8c0984e5SSebastian Reichel 	.remove		= max77693_charger_remove,
765*8c0984e5SSebastian Reichel 	.id_table	= max77693_charger_id,
766*8c0984e5SSebastian Reichel };
767*8c0984e5SSebastian Reichel module_platform_driver(max77693_charger_driver);
768*8c0984e5SSebastian Reichel 
769*8c0984e5SSebastian Reichel MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
770*8c0984e5SSebastian Reichel MODULE_DESCRIPTION("Maxim 77693 charger driver");
771*8c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
772