xref: /linux/drivers/power/supply/mt6360_charger.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2021 MediaTek Inc.
4  */
5 
6 #include <linux/devm-helpers.h>
7 #include <linux/init.h>
8 #include <linux/interrupt.h>
9 #include <linux/kernel.h>
10 #include <linux/linear_range.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/platform_device.h>
14 #include <linux/power_supply.h>
15 #include <linux/property.h>
16 #include <linux/regmap.h>
17 #include <linux/regulator/driver.h>
18 
19 #define MT6360_PMU_CHG_CTRL1	0x311
20 #define MT6360_PMU_CHG_CTRL2	0x312
21 #define MT6360_PMU_CHG_CTRL3	0x313
22 #define MT6360_PMU_CHG_CTRL4	0x314
23 #define MT6360_PMU_CHG_CTRL5	0x315
24 #define MT6360_PMU_CHG_CTRL6	0x316
25 #define MT6360_PMU_CHG_CTRL7	0x317
26 #define MT6360_PMU_CHG_CTRL8	0x318
27 #define MT6360_PMU_CHG_CTRL9	0x319
28 #define MT6360_PMU_CHG_CTRL10	0x31A
29 #define MT6360_PMU_DEVICE_TYPE	0x322
30 #define MT6360_PMU_USB_STATUS1	0x327
31 #define MT6360_PMU_CHG_STAT	0x34A
32 #define MT6360_PMU_CHG_CTRL19	0x361
33 #define MT6360_PMU_FOD_STAT	0x3E7
34 
35 /* MT6360_PMU_CHG_CTRL1 */
36 #define MT6360_FSLP_SHFT	(3)
37 #define MT6360_FSLP_MASK	BIT(MT6360_FSLP_SHFT)
38 #define MT6360_OPA_MODE_SHFT	(0)
39 #define MT6360_OPA_MODE_MASK	BIT(MT6360_OPA_MODE_SHFT)
40 /* MT6360_PMU_CHG_CTRL2 */
41 #define MT6360_IINLMTSEL_SHFT	(2)
42 #define MT6360_IINLMTSEL_MASK	GENMASK(3, 2)
43 /* MT6360_PMU_CHG_CTRL3 */
44 #define MT6360_IAICR_SHFT	(2)
45 #define MT6360_IAICR_MASK	GENMASK(7, 2)
46 #define MT6360_ILIM_EN_MASK	BIT(0)
47 /* MT6360_PMU_CHG_CTRL4 */
48 #define MT6360_VOREG_SHFT	(1)
49 #define MT6360_VOREG_MASK	GENMASK(7, 1)
50 /* MT6360_PMU_CHG_CTRL5 */
51 #define MT6360_VOBST_MASK	GENMASK(7, 2)
52 /* MT6360_PMU_CHG_CTRL6 */
53 #define MT6360_VMIVR_SHFT      (1)
54 #define MT6360_VMIVR_MASK      GENMASK(7, 1)
55 /* MT6360_PMU_CHG_CTRL7 */
56 #define MT6360_ICHG_SHFT	(2)
57 #define MT6360_ICHG_MASK	GENMASK(7, 2)
58 /* MT6360_PMU_CHG_CTRL8 */
59 #define MT6360_IPREC_SHFT	(0)
60 #define MT6360_IPREC_MASK	GENMASK(3, 0)
61 /* MT6360_PMU_CHG_CTRL9 */
62 #define MT6360_IEOC_SHFT	(4)
63 #define MT6360_IEOC_MASK	GENMASK(7, 4)
64 /* MT6360_PMU_CHG_CTRL10 */
65 #define MT6360_OTG_OC_MASK	GENMASK(3, 0)
66 /* MT6360_PMU_DEVICE_TYPE */
67 #define MT6360_USBCHGEN_MASK	BIT(7)
68 /* MT6360_PMU_USB_STATUS1 */
69 #define MT6360_USB_STATUS_SHFT	(4)
70 #define MT6360_USB_STATUS_MASK	GENMASK(6, 4)
71 /* MT6360_PMU_CHG_STAT */
72 #define MT6360_CHG_STAT_SHFT	(6)
73 #define MT6360_CHG_STAT_MASK	GENMASK(7, 6)
74 #define MT6360_VBAT_LVL_MASK	BIT(5)
75 /* MT6360_PMU_CHG_CTRL19 */
76 #define MT6360_VINOVP_SHFT	(5)
77 #define MT6360_VINOVP_MASK	GENMASK(6, 5)
78 /* MT6360_PMU_FOD_STAT */
79 #define MT6360_CHRDET_EXT_MASK	BIT(4)
80 
81 /* uV */
82 #define MT6360_VMIVR_MIN	3900000
83 #define MT6360_VMIVR_MAX	13400000
84 #define MT6360_VMIVR_STEP	100000
85 /* uA */
86 #define MT6360_ICHG_MIN		100000
87 #define MT6360_ICHG_MAX		5000000
88 #define MT6360_ICHG_STEP	100000
89 /* uV */
90 #define MT6360_VOREG_MIN	3900000
91 #define MT6360_VOREG_MAX	4710000
92 #define MT6360_VOREG_STEP	10000
93 /* uA */
94 #define MT6360_AICR_MIN		100000
95 #define MT6360_AICR_MAX		3250000
96 #define MT6360_AICR_STEP	50000
97 /* uA */
98 #define MT6360_IPREC_MIN	100000
99 #define MT6360_IPREC_MAX	850000
100 #define MT6360_IPREC_STEP	50000
101 /* uA */
102 #define MT6360_IEOC_MIN		100000
103 #define MT6360_IEOC_MAX		850000
104 #define MT6360_IEOC_STEP	50000
105 
106 enum {
107 	MT6360_RANGE_VMIVR,
108 	MT6360_RANGE_ICHG,
109 	MT6360_RANGE_VOREG,
110 	MT6360_RANGE_AICR,
111 	MT6360_RANGE_IPREC,
112 	MT6360_RANGE_IEOC,
113 	MT6360_RANGE_MAX,
114 };
115 
116 static const struct linear_range mt6360_chg_range[MT6360_RANGE_MAX] = {
117 	LINEAR_RANGE_IDX(MT6360_RANGE_VMIVR, 3900000, 0, 0x5F, 100000),
118 	LINEAR_RANGE_IDX(MT6360_RANGE_ICHG, 100000, 0, 0x31, 100000),
119 	LINEAR_RANGE_IDX(MT6360_RANGE_VOREG, 3900000, 0, 0x51, 10000),
120 	LINEAR_RANGE_IDX(MT6360_RANGE_AICR, 100000, 0, 0x3F, 50000),
121 	LINEAR_RANGE_IDX(MT6360_RANGE_IPREC, 100000, 0, 0x0F, 50000),
122 	LINEAR_RANGE_IDX(MT6360_RANGE_IEOC, 100000, 0, 0x0F, 50000),
123 };
124 
125 struct mt6360_chg_info {
126 	struct device *dev;
127 	struct regmap *regmap;
128 	struct power_supply_desc psy_desc;
129 	struct power_supply *psy;
130 	struct regulator_dev *otg_rdev;
131 	struct mutex chgdet_lock;
132 	u32 vinovp;
133 	bool pwr_rdy;
134 	bool bc12_en;
135 	int psy_usb_type;
136 	struct work_struct chrdet_work;
137 };
138 
139 enum mt6360_iinlmtsel {
140 	MT6360_IINLMTSEL_AICR_3250 = 0,
141 	MT6360_IINLMTSEL_CHG_TYPE,
142 	MT6360_IINLMTSEL_AICR,
143 	MT6360_IINLMTSEL_LOWER_LEVEL,
144 };
145 
146 enum mt6360_pmu_chg_type {
147 	MT6360_CHG_TYPE_NOVBUS = 0,
148 	MT6360_CHG_TYPE_UNDER_GOING,
149 	MT6360_CHG_TYPE_SDP,
150 	MT6360_CHG_TYPE_SDPNSTD,
151 	MT6360_CHG_TYPE_DCP,
152 	MT6360_CHG_TYPE_CDP,
153 	MT6360_CHG_TYPE_DISABLE_BC12,
154 	MT6360_CHG_TYPE_MAX,
155 };
156 
mt6360_get_chrdet_ext_stat(struct mt6360_chg_info * mci,bool * pwr_rdy)157 static int mt6360_get_chrdet_ext_stat(struct mt6360_chg_info *mci,
158 					     bool *pwr_rdy)
159 {
160 	int ret;
161 	unsigned int regval;
162 
163 	ret = regmap_read(mci->regmap, MT6360_PMU_FOD_STAT, &regval);
164 	if (ret < 0)
165 		return ret;
166 	*pwr_rdy = (regval & MT6360_CHRDET_EXT_MASK) ? true : false;
167 	return 0;
168 }
169 
mt6360_charger_get_online(struct mt6360_chg_info * mci,union power_supply_propval * val)170 static int mt6360_charger_get_online(struct mt6360_chg_info *mci,
171 				     union power_supply_propval *val)
172 {
173 	int ret;
174 	bool pwr_rdy;
175 
176 	ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
177 	if (ret < 0)
178 		return ret;
179 	val->intval = pwr_rdy ? true : false;
180 	return 0;
181 }
182 
mt6360_charger_get_status(struct mt6360_chg_info * mci,union power_supply_propval * val)183 static int mt6360_charger_get_status(struct mt6360_chg_info *mci,
184 				     union power_supply_propval *val)
185 {
186 	int status, ret;
187 	unsigned int regval;
188 	bool pwr_rdy;
189 
190 	ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
191 	if (ret < 0)
192 		return ret;
193 	if (!pwr_rdy) {
194 		status = POWER_SUPPLY_STATUS_DISCHARGING;
195 		goto out;
196 	}
197 
198 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, &regval);
199 	if (ret < 0)
200 		return ret;
201 	regval &= MT6360_CHG_STAT_MASK;
202 	regval >>= MT6360_CHG_STAT_SHFT;
203 	switch (regval) {
204 	case 0x0:
205 		status = POWER_SUPPLY_STATUS_NOT_CHARGING;
206 		break;
207 	case 0x1:
208 		status = POWER_SUPPLY_STATUS_CHARGING;
209 		break;
210 	case 0x2:
211 		status = POWER_SUPPLY_STATUS_FULL;
212 		break;
213 	default:
214 		ret = -EIO;
215 	}
216 out:
217 	if (!ret)
218 		val->intval = status;
219 	return ret;
220 }
221 
mt6360_charger_get_charge_type(struct mt6360_chg_info * mci,union power_supply_propval * val)222 static int mt6360_charger_get_charge_type(struct mt6360_chg_info *mci,
223 					  union power_supply_propval *val)
224 {
225 	int type, ret;
226 	unsigned int regval;
227 	u8 chg_stat;
228 
229 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, &regval);
230 	if (ret < 0)
231 		return ret;
232 
233 	chg_stat = (regval & MT6360_CHG_STAT_MASK) >> MT6360_CHG_STAT_SHFT;
234 	switch (chg_stat) {
235 	case 0x01: /* Charge in Progress */
236 		if (regval & MT6360_VBAT_LVL_MASK)
237 			type = POWER_SUPPLY_CHARGE_TYPE_FAST;
238 		else
239 			type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
240 		break;
241 	case 0x00: /* Not Charging */
242 	case 0x02: /* Charge Done */
243 	case 0x03: /* Charge Fault */
244 	default:
245 		type = POWER_SUPPLY_CHARGE_TYPE_NONE;
246 		break;
247 	}
248 
249 	val->intval = type;
250 	return 0;
251 }
252 
mt6360_charger_get_ichg(struct mt6360_chg_info * mci,union power_supply_propval * val)253 static int mt6360_charger_get_ichg(struct mt6360_chg_info *mci,
254 				   union power_supply_propval *val)
255 {
256 	int ret;
257 	u32 sel, value;
258 
259 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL7, &sel);
260 	if (ret < 0)
261 		return ret;
262 	sel = (sel & MT6360_ICHG_MASK) >> MT6360_ICHG_SHFT;
263 	ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_ICHG], sel, &value);
264 	if (!ret)
265 		val->intval = value;
266 	return ret;
267 }
268 
mt6360_charger_get_max_ichg(struct mt6360_chg_info * mci,union power_supply_propval * val)269 static int mt6360_charger_get_max_ichg(struct mt6360_chg_info *mci,
270 				       union power_supply_propval *val)
271 {
272 	val->intval = MT6360_ICHG_MAX;
273 	return 0;
274 }
275 
mt6360_charger_get_cv(struct mt6360_chg_info * mci,union power_supply_propval * val)276 static int mt6360_charger_get_cv(struct mt6360_chg_info *mci,
277 				 union power_supply_propval *val)
278 {
279 	int ret;
280 	u32 sel, value;
281 
282 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL4, &sel);
283 	if (ret < 0)
284 		return ret;
285 	sel = (sel & MT6360_VOREG_MASK) >> MT6360_VOREG_SHFT;
286 	ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VOREG], sel, &value);
287 	if (!ret)
288 		val->intval = value;
289 	return ret;
290 }
291 
mt6360_charger_get_max_cv(struct mt6360_chg_info * mci,union power_supply_propval * val)292 static int mt6360_charger_get_max_cv(struct mt6360_chg_info *mci,
293 				     union power_supply_propval *val)
294 {
295 	val->intval = MT6360_VOREG_MAX;
296 	return 0;
297 }
298 
mt6360_charger_get_aicr(struct mt6360_chg_info * mci,union power_supply_propval * val)299 static int mt6360_charger_get_aicr(struct mt6360_chg_info *mci,
300 				   union power_supply_propval *val)
301 {
302 	int ret;
303 	u32 sel, value;
304 
305 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL3, &sel);
306 	if (ret < 0)
307 		return ret;
308 	sel = (sel & MT6360_IAICR_MASK) >> MT6360_IAICR_SHFT;
309 	ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_AICR], sel, &value);
310 	if (!ret)
311 		val->intval = value;
312 	return ret;
313 }
314 
mt6360_charger_get_mivr(struct mt6360_chg_info * mci,union power_supply_propval * val)315 static int mt6360_charger_get_mivr(struct mt6360_chg_info *mci,
316 				   union power_supply_propval *val)
317 {
318 	int ret;
319 	u32 sel, value;
320 
321 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL6, &sel);
322 	if (ret < 0)
323 		return ret;
324 	sel = (sel & MT6360_VMIVR_MASK) >> MT6360_VMIVR_SHFT;
325 	ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VMIVR], sel, &value);
326 	if (!ret)
327 		val->intval = value;
328 	return ret;
329 }
330 
mt6360_charger_get_iprechg(struct mt6360_chg_info * mci,union power_supply_propval * val)331 static int mt6360_charger_get_iprechg(struct mt6360_chg_info *mci,
332 				      union power_supply_propval *val)
333 {
334 	int ret;
335 	u32 sel, value;
336 
337 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL8, &sel);
338 	if (ret < 0)
339 		return ret;
340 	sel = (sel & MT6360_IPREC_MASK) >> MT6360_IPREC_SHFT;
341 	ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IPREC], sel, &value);
342 	if (!ret)
343 		val->intval = value;
344 	return ret;
345 }
346 
mt6360_charger_get_ieoc(struct mt6360_chg_info * mci,union power_supply_propval * val)347 static int mt6360_charger_get_ieoc(struct mt6360_chg_info *mci,
348 				   union power_supply_propval *val)
349 {
350 	int ret;
351 	u32 sel, value;
352 
353 	ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL9, &sel);
354 	if (ret < 0)
355 		return ret;
356 	sel = (sel & MT6360_IEOC_MASK) >> MT6360_IEOC_SHFT;
357 	ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IEOC], sel, &value);
358 	if (!ret)
359 		val->intval = value;
360 	return ret;
361 }
362 
mt6360_charger_set_online(struct mt6360_chg_info * mci,const union power_supply_propval * val)363 static int mt6360_charger_set_online(struct mt6360_chg_info *mci,
364 				     const union power_supply_propval *val)
365 {
366 	u8 force_sleep = val->intval ? 0 : 1;
367 
368 	return regmap_update_bits(mci->regmap,
369 				  MT6360_PMU_CHG_CTRL1,
370 				  MT6360_FSLP_MASK,
371 				  force_sleep << MT6360_FSLP_SHFT);
372 }
373 
mt6360_charger_set_ichg(struct mt6360_chg_info * mci,const union power_supply_propval * val)374 static int mt6360_charger_set_ichg(struct mt6360_chg_info *mci,
375 				   const union power_supply_propval *val)
376 {
377 	u32 sel;
378 
379 	linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_ICHG], val->intval, &sel);
380 	return regmap_update_bits(mci->regmap,
381 				  MT6360_PMU_CHG_CTRL7,
382 				  MT6360_ICHG_MASK,
383 				  sel << MT6360_ICHG_SHFT);
384 }
385 
mt6360_charger_set_cv(struct mt6360_chg_info * mci,const union power_supply_propval * val)386 static int mt6360_charger_set_cv(struct mt6360_chg_info *mci,
387 				 const union power_supply_propval *val)
388 {
389 	u32 sel;
390 
391 	linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VOREG], val->intval, &sel);
392 	return regmap_update_bits(mci->regmap,
393 				  MT6360_PMU_CHG_CTRL4,
394 				  MT6360_VOREG_MASK,
395 				  sel << MT6360_VOREG_SHFT);
396 }
397 
mt6360_charger_set_aicr(struct mt6360_chg_info * mci,const union power_supply_propval * val)398 static int mt6360_charger_set_aicr(struct mt6360_chg_info *mci,
399 				   const union power_supply_propval *val)
400 {
401 	u32 sel;
402 
403 	linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_AICR], val->intval, &sel);
404 	return regmap_update_bits(mci->regmap,
405 				  MT6360_PMU_CHG_CTRL3,
406 				  MT6360_IAICR_MASK,
407 				  sel << MT6360_IAICR_SHFT);
408 }
409 
mt6360_charger_set_mivr(struct mt6360_chg_info * mci,const union power_supply_propval * val)410 static int mt6360_charger_set_mivr(struct mt6360_chg_info *mci,
411 				   const union power_supply_propval *val)
412 {
413 	u32 sel;
414 
415 	linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VMIVR], val->intval, &sel);
416 	return regmap_update_bits(mci->regmap,
417 				  MT6360_PMU_CHG_CTRL3,
418 				  MT6360_VMIVR_MASK,
419 				  sel << MT6360_VMIVR_SHFT);
420 }
421 
mt6360_charger_set_iprechg(struct mt6360_chg_info * mci,const union power_supply_propval * val)422 static int mt6360_charger_set_iprechg(struct mt6360_chg_info *mci,
423 				      const union power_supply_propval *val)
424 {
425 	u32 sel;
426 
427 	linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IPREC], val->intval, &sel);
428 	return regmap_update_bits(mci->regmap,
429 				  MT6360_PMU_CHG_CTRL8,
430 				  MT6360_IPREC_MASK,
431 				  sel << MT6360_IPREC_SHFT);
432 }
433 
mt6360_charger_set_ieoc(struct mt6360_chg_info * mci,const union power_supply_propval * val)434 static int mt6360_charger_set_ieoc(struct mt6360_chg_info *mci,
435 				   const union power_supply_propval *val)
436 {
437 	u32 sel;
438 
439 	linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IEOC], val->intval, &sel);
440 	return regmap_update_bits(mci->regmap,
441 				  MT6360_PMU_CHG_CTRL9,
442 				  MT6360_IEOC_MASK,
443 				  sel << MT6360_IEOC_SHFT);
444 }
445 
mt6360_charger_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)446 static int mt6360_charger_get_property(struct power_supply *psy,
447 				       enum power_supply_property psp,
448 				       union power_supply_propval *val)
449 {
450 	struct mt6360_chg_info *mci = power_supply_get_drvdata(psy);
451 	int ret = 0;
452 
453 	switch (psp) {
454 	case POWER_SUPPLY_PROP_ONLINE:
455 		ret = mt6360_charger_get_online(mci, val);
456 		break;
457 	case POWER_SUPPLY_PROP_STATUS:
458 		ret = mt6360_charger_get_status(mci, val);
459 		break;
460 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
461 		ret = mt6360_charger_get_charge_type(mci, val);
462 		break;
463 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
464 		ret = mt6360_charger_get_ichg(mci, val);
465 		break;
466 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
467 		ret = mt6360_charger_get_max_ichg(mci, val);
468 		break;
469 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
470 		ret = mt6360_charger_get_cv(mci, val);
471 		break;
472 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
473 		ret = mt6360_charger_get_max_cv(mci, val);
474 		break;
475 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
476 		ret = mt6360_charger_get_aicr(mci, val);
477 		break;
478 	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
479 		ret = mt6360_charger_get_mivr(mci, val);
480 		break;
481 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
482 		ret = mt6360_charger_get_iprechg(mci, val);
483 		break;
484 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
485 		ret = mt6360_charger_get_ieoc(mci, val);
486 		break;
487 	case POWER_SUPPLY_PROP_USB_TYPE:
488 		val->intval = mci->psy_usb_type;
489 		break;
490 	default:
491 		ret = -ENODATA;
492 	}
493 	return ret;
494 }
495 
mt6360_charger_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)496 static int mt6360_charger_set_property(struct power_supply *psy,
497 				       enum power_supply_property psp,
498 				       const union power_supply_propval *val)
499 {
500 	struct mt6360_chg_info *mci = power_supply_get_drvdata(psy);
501 	int ret;
502 
503 	switch (psp) {
504 	case POWER_SUPPLY_PROP_ONLINE:
505 		ret = mt6360_charger_set_online(mci, val);
506 		break;
507 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
508 		ret = mt6360_charger_set_ichg(mci, val);
509 		break;
510 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
511 		ret = mt6360_charger_set_cv(mci, val);
512 		break;
513 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
514 		ret = mt6360_charger_set_aicr(mci, val);
515 		break;
516 	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
517 		ret = mt6360_charger_set_mivr(mci, val);
518 		break;
519 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
520 		ret = mt6360_charger_set_iprechg(mci, val);
521 		break;
522 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
523 		ret = mt6360_charger_set_ieoc(mci, val);
524 		break;
525 	default:
526 		ret = -EINVAL;
527 	}
528 	return ret;
529 }
530 
mt6360_charger_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)531 static int mt6360_charger_property_is_writeable(struct power_supply *psy,
532 					       enum power_supply_property psp)
533 {
534 	switch (psp) {
535 	case POWER_SUPPLY_PROP_ONLINE:
536 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
537 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
538 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
539 	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
540 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
541 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
542 		return 1;
543 	default:
544 		return 0;
545 	}
546 }
547 
548 static enum power_supply_property mt6360_charger_properties[] = {
549 	POWER_SUPPLY_PROP_ONLINE,
550 	POWER_SUPPLY_PROP_STATUS,
551 	POWER_SUPPLY_PROP_CHARGE_TYPE,
552 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
553 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
554 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
555 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
556 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
557 	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
558 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
559 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
560 	POWER_SUPPLY_PROP_USB_TYPE,
561 };
562 
563 static const struct power_supply_desc mt6360_charger_desc = {
564 	.type			= POWER_SUPPLY_TYPE_USB,
565 	.properties		= mt6360_charger_properties,
566 	.num_properties		= ARRAY_SIZE(mt6360_charger_properties),
567 	.get_property		= mt6360_charger_get_property,
568 	.set_property		= mt6360_charger_set_property,
569 	.property_is_writeable	= mt6360_charger_property_is_writeable,
570 	.usb_types		= BIT(POWER_SUPPLY_USB_TYPE_SDP) |
571 				  BIT(POWER_SUPPLY_USB_TYPE_CDP) |
572 				  BIT(POWER_SUPPLY_USB_TYPE_DCP) |
573 				  BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
574 };
575 
576 static const struct regulator_ops mt6360_chg_otg_ops = {
577 	.list_voltage = regulator_list_voltage_linear,
578 	.enable = regulator_enable_regmap,
579 	.disable = regulator_disable_regmap,
580 	.is_enabled = regulator_is_enabled_regmap,
581 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
582 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
583 };
584 
585 static const struct regulator_desc mt6360_otg_rdesc = {
586 	.of_match = "usb-otg-vbus-regulator",
587 	.name = "usb-otg-vbus",
588 	.ops = &mt6360_chg_otg_ops,
589 	.owner = THIS_MODULE,
590 	.type = REGULATOR_VOLTAGE,
591 	.min_uV = 4425000,
592 	.uV_step = 25000,
593 	.n_voltages = 57,
594 	.vsel_reg = MT6360_PMU_CHG_CTRL5,
595 	.vsel_mask = MT6360_VOBST_MASK,
596 	.enable_reg = MT6360_PMU_CHG_CTRL1,
597 	.enable_mask = MT6360_OPA_MODE_MASK,
598 };
599 
mt6360_pmu_attach_i_handler(int irq,void * data)600 static irqreturn_t mt6360_pmu_attach_i_handler(int irq, void *data)
601 {
602 	struct mt6360_chg_info *mci = data;
603 	int ret;
604 	unsigned int usb_status;
605 	int last_usb_type;
606 
607 	mutex_lock(&mci->chgdet_lock);
608 	if (!mci->bc12_en) {
609 		dev_warn(mci->dev, "Received attach interrupt, bc12 disabled, ignore irq\n");
610 		goto out;
611 	}
612 	last_usb_type = mci->psy_usb_type;
613 	/* Plug in */
614 	ret = regmap_read(mci->regmap, MT6360_PMU_USB_STATUS1, &usb_status);
615 	if (ret < 0)
616 		goto out;
617 	usb_status &= MT6360_USB_STATUS_MASK;
618 	usb_status >>= MT6360_USB_STATUS_SHFT;
619 	switch (usb_status) {
620 	case MT6360_CHG_TYPE_NOVBUS:
621 		dev_dbg(mci->dev, "Received attach interrupt, no vbus\n");
622 		goto out;
623 	case MT6360_CHG_TYPE_UNDER_GOING:
624 		dev_dbg(mci->dev, "Received attach interrupt, under going...\n");
625 		goto out;
626 	case MT6360_CHG_TYPE_SDP:
627 		mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
628 		break;
629 	case MT6360_CHG_TYPE_SDPNSTD:
630 		mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
631 		break;
632 	case MT6360_CHG_TYPE_CDP:
633 		mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;
634 		break;
635 	case MT6360_CHG_TYPE_DCP:
636 		mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
637 		break;
638 	case MT6360_CHG_TYPE_DISABLE_BC12:
639 		dev_dbg(mci->dev, "Received attach interrupt, bc12 detect not enable\n");
640 		goto out;
641 	default:
642 		mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
643 		dev_dbg(mci->dev, "Received attach interrupt, reserved address\n");
644 		goto out;
645 	}
646 
647 	dev_dbg(mci->dev, "Received attach interrupt, chg_type = %d\n", mci->psy_usb_type);
648 	if (last_usb_type != mci->psy_usb_type)
649 		power_supply_changed(mci->psy);
650 out:
651 	mutex_unlock(&mci->chgdet_lock);
652 	return IRQ_HANDLED;
653 }
654 
mt6360_handle_chrdet_ext_evt(struct mt6360_chg_info * mci)655 static void mt6360_handle_chrdet_ext_evt(struct mt6360_chg_info *mci)
656 {
657 	int ret;
658 	bool pwr_rdy;
659 
660 	mutex_lock(&mci->chgdet_lock);
661 	ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
662 	if (ret < 0)
663 		goto out;
664 	if (mci->pwr_rdy == pwr_rdy) {
665 		dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy is same(%d)\n", pwr_rdy);
666 		goto out;
667 	}
668 	mci->pwr_rdy = pwr_rdy;
669 	dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy = %d\n", pwr_rdy);
670 	if (!pwr_rdy) {
671 		mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
672 		power_supply_changed(mci->psy);
673 
674 	}
675 	ret = regmap_update_bits(mci->regmap,
676 				 MT6360_PMU_DEVICE_TYPE,
677 				 MT6360_USBCHGEN_MASK,
678 				 pwr_rdy ? MT6360_USBCHGEN_MASK : 0);
679 	if (ret < 0)
680 		goto out;
681 	mci->bc12_en = pwr_rdy;
682 out:
683 	mutex_unlock(&mci->chgdet_lock);
684 }
685 
mt6360_chrdet_work(struct work_struct * work)686 static void mt6360_chrdet_work(struct work_struct *work)
687 {
688 	struct mt6360_chg_info *mci = (struct mt6360_chg_info *)container_of(
689 				     work, struct mt6360_chg_info, chrdet_work);
690 
691 	mt6360_handle_chrdet_ext_evt(mci);
692 }
693 
mt6360_pmu_chrdet_ext_evt_handler(int irq,void * data)694 static irqreturn_t mt6360_pmu_chrdet_ext_evt_handler(int irq, void *data)
695 {
696 	struct mt6360_chg_info *mci = data;
697 
698 	mt6360_handle_chrdet_ext_evt(mci);
699 	return IRQ_HANDLED;
700 }
701 
mt6360_chg_irq_register(struct platform_device * pdev)702 static int mt6360_chg_irq_register(struct platform_device *pdev)
703 {
704 	const struct {
705 		const char *name;
706 		irq_handler_t handler;
707 	} irq_descs[] = {
708 		{ "attach_i", mt6360_pmu_attach_i_handler },
709 		{ "chrdet_ext_evt", mt6360_pmu_chrdet_ext_evt_handler }
710 	};
711 	int i, ret;
712 
713 	for (i = 0; i < ARRAY_SIZE(irq_descs); i++) {
714 		ret = platform_get_irq_byname(pdev, irq_descs[i].name);
715 		if (ret < 0)
716 			return ret;
717 
718 		ret = devm_request_threaded_irq(&pdev->dev, ret, NULL,
719 						irq_descs[i].handler,
720 						IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
721 						irq_descs[i].name,
722 						platform_get_drvdata(pdev));
723 		if (ret < 0)
724 			return dev_err_probe(&pdev->dev, ret, "Failed to request %s irq\n",
725 					     irq_descs[i].name);
726 	}
727 
728 	return 0;
729 }
730 
mt6360_vinovp_trans_to_sel(u32 val)731 static u32 mt6360_vinovp_trans_to_sel(u32 val)
732 {
733 	u32 vinovp_tbl[] = { 5500000, 6500000, 11000000, 14500000 };
734 	int i;
735 
736 	/* Select the smaller and equal supported value */
737 	for (i = 0; i < ARRAY_SIZE(vinovp_tbl)-1; i++) {
738 		if (val < vinovp_tbl[i+1])
739 			break;
740 	}
741 	return i;
742 }
743 
mt6360_chg_init_setting(struct mt6360_chg_info * mci)744 static int mt6360_chg_init_setting(struct mt6360_chg_info *mci)
745 {
746 	int ret;
747 	u32 sel;
748 
749 	sel = mt6360_vinovp_trans_to_sel(mci->vinovp);
750 	ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL19,
751 				  MT6360_VINOVP_MASK, sel << MT6360_VINOVP_SHFT);
752 	if (ret)
753 		return dev_err_probe(mci->dev, ret, "%s: Failed to apply vinovp\n", __func__);
754 	ret = regmap_update_bits(mci->regmap, MT6360_PMU_DEVICE_TYPE,
755 				 MT6360_USBCHGEN_MASK, 0);
756 	if (ret)
757 		return dev_err_probe(mci->dev, ret, "%s: Failed to disable bc12\n", __func__);
758 	ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL2,
759 				 MT6360_IINLMTSEL_MASK,
760 				 MT6360_IINLMTSEL_AICR <<
761 					MT6360_IINLMTSEL_SHFT);
762 	if (ret)
763 		return dev_err_probe(mci->dev, ret,
764 				     "%s: Failed to switch iinlmtsel to aicr\n", __func__);
765 	usleep_range(5000, 6000);
766 	ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL3,
767 				 MT6360_ILIM_EN_MASK, 0);
768 	if (ret)
769 		return dev_err_probe(mci->dev, ret,
770 				     "%s: Failed to disable ilim\n", __func__);
771 	ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL10,
772 				 MT6360_OTG_OC_MASK, MT6360_OTG_OC_MASK);
773 	if (ret)
774 		return dev_err_probe(mci->dev, ret,
775 				     "%s: Failed to config otg oc to 3A\n", __func__);
776 	return 0;
777 }
778 
mt6360_charger_probe(struct platform_device * pdev)779 static int mt6360_charger_probe(struct platform_device *pdev)
780 {
781 	struct mt6360_chg_info *mci;
782 	struct power_supply_config charger_cfg = {};
783 	struct regulator_config config = { };
784 	int ret;
785 
786 	mci = devm_kzalloc(&pdev->dev, sizeof(*mci), GFP_KERNEL);
787 	if (!mci)
788 		return -ENOMEM;
789 
790 	mci->dev = &pdev->dev;
791 	mci->vinovp = 6500000;
792 	mutex_init(&mci->chgdet_lock);
793 	platform_set_drvdata(pdev, mci);
794 	ret = devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work);
795 	if (ret)
796 		return dev_err_probe(&pdev->dev, ret, "Failed to set delayed work\n");
797 
798 	ret = device_property_read_u32(&pdev->dev, "richtek,vinovp-microvolt", &mci->vinovp);
799 	if (ret)
800 		dev_warn(&pdev->dev, "Failed to parse vinovp in DT, keep default 6.5v\n");
801 
802 	mci->regmap = dev_get_regmap(pdev->dev.parent, NULL);
803 	if (!mci->regmap)
804 		return dev_err_probe(&pdev->dev, -ENODEV, "Failed to get parent regmap\n");
805 
806 	ret = mt6360_chg_init_setting(mci);
807 	if (ret)
808 		return dev_err_probe(&pdev->dev, ret, "Failed to initial setting\n");
809 
810 	memcpy(&mci->psy_desc, &mt6360_charger_desc, sizeof(mci->psy_desc));
811 	mci->psy_desc.name = dev_name(&pdev->dev);
812 	charger_cfg.drv_data = mci;
813 	charger_cfg.of_node = pdev->dev.of_node;
814 	mci->psy = devm_power_supply_register(&pdev->dev,
815 					      &mci->psy_desc, &charger_cfg);
816 	if (IS_ERR(mci->psy))
817 		return dev_err_probe(&pdev->dev, PTR_ERR(mci->psy),
818 				     "Failed to register power supply dev\n");
819 
820 
821 	ret = mt6360_chg_irq_register(pdev);
822 	if (ret)
823 		return dev_err_probe(&pdev->dev, ret, "Failed to register irqs\n");
824 
825 	config.dev = &pdev->dev;
826 	config.regmap = mci->regmap;
827 	mci->otg_rdev = devm_regulator_register(&pdev->dev, &mt6360_otg_rdesc,
828 						&config);
829 	if (IS_ERR(mci->otg_rdev))
830 		return PTR_ERR(mci->otg_rdev);
831 
832 	schedule_work(&mci->chrdet_work);
833 
834 	return 0;
835 }
836 
837 static const struct of_device_id __maybe_unused mt6360_charger_of_id[] = {
838 	{ .compatible = "mediatek,mt6360-chg", },
839 	{},
840 };
841 MODULE_DEVICE_TABLE(of, mt6360_charger_of_id);
842 
843 static const struct platform_device_id mt6360_charger_id[] = {
844 	{ "mt6360-chg", 0 },
845 	{},
846 };
847 MODULE_DEVICE_TABLE(platform, mt6360_charger_id);
848 
849 static struct platform_driver mt6360_charger_driver = {
850 	.driver = {
851 		.name = "mt6360-chg",
852 		.of_match_table = of_match_ptr(mt6360_charger_of_id),
853 	},
854 	.probe = mt6360_charger_probe,
855 	.id_table = mt6360_charger_id,
856 };
857 module_platform_driver(mt6360_charger_driver);
858 
859 MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>");
860 MODULE_DESCRIPTION("MT6360 Charger Driver");
861 MODULE_LICENSE("GPL");
862