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 106enum { 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 116static 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 125struct 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 139enum mt6360_iinlmtsel { 140 MT6360_IINLMTSEL_AICR_3250 = 0, 141 MT6360_IINLMTSEL_CHG_TYPE, 142 MT6360_IINLMTSEL_AICR, 143 MT6360_IINLMTSEL_LOWER_LEVEL, 144}; 145 146enum 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 157static 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 164static 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 177static 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 190static 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 } 223out: 224 if (!ret) 225 val->intval = status; 226 return ret; 227} 228 229static 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 260static 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 276static 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 283static 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 299static 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 306static 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 322static 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 338static 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 354static 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 370static 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 381static 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 393static 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 405static 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 417static 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 429static 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 441static 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 453static 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 503static 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 538static 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 555static 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 570static 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 581static 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 590static 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 605static 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); 655out: 656 mutex_unlock(&mci->chgdet_lock); 657 return IRQ_HANDLED; 658} 659 660static 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; 687out: 688 mutex_unlock(&mci->chgdet_lock); 689} 690 691static 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 699static 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 707static 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 736static 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 749static 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 784static 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 842static const struct of_device_id __maybe_unused mt6360_charger_of_id[] = { 843 { .compatible = "mediatek,mt6360-chg", }, 844 {}, 845}; 846MODULE_DEVICE_TABLE(of, mt6360_charger_of_id); 847 848static const struct platform_device_id mt6360_charger_id[] = { 849 { "mt6360-chg", 0 }, 850 {}, 851}; 852MODULE_DEVICE_TABLE(platform, mt6360_charger_id); 853 854static 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}; 862module_platform_driver(mt6360_charger_driver); 863 864MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>"); 865MODULE_DESCRIPTION("MT6360 Charger Driver"); 866MODULE_LICENSE("GPL"); 867