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