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