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, ®val);
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, ®val);
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, ®val);
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