FILE
mt6360_charger.c
File preview with syntax highlighting.
linux-6.19.14/drivers/power/supply/mt6360_charger.c
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 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 170static 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 183static 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 } 216out: 217 if (!ret) 218 val->intval = status; 219 return ret; 220} 221 222static 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 253static 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 269static 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 276static 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 292static 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 299static 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 315static 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 331static 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 347static 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 363static 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 374static 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 386static 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 398static 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 410static 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 422static 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 434static 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 446static 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 496static 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 531static 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 548static 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 563static 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 576static 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 585static 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 600static 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); 650out: 651 mutex_unlock(&mci->chgdet_lock); 652 return IRQ_HANDLED; 653} 654 655static 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; 682out: 683 mutex_unlock(&mci->chgdet_lock); 684} 685 686static 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 694static 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 702static 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 731static 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 744static 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 779static 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.fwnode = dev_fwnode(&pdev->dev); 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 837static const struct of_device_id __maybe_unused mt6360_charger_of_id[] = { 838 { .compatible = "mediatek,mt6360-chg", }, 839 {}, 840}; 841MODULE_DEVICE_TABLE(of, mt6360_charger_of_id); 842 843static const struct platform_device_id mt6360_charger_id[] = { 844 { "mt6360-chg", 0 }, 845 {}, 846}; 847MODULE_DEVICE_TABLE(platform, mt6360_charger_id); 848 849static 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}; 857module_platform_driver(mt6360_charger_driver); 858 859MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>"); 860MODULE_DESCRIPTION("MT6360 Charger Driver"); 861MODULE_LICENSE("GPL");
~/
Read-only file preview.