0001
0002
0003
0004
0005
0006 #include <linux/devm-helpers.h>
0007 #include <linux/init.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/kernel.h>
0010 #include <linux/linear_range.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/power_supply.h>
0015 #include <linux/property.h>
0016 #include <linux/regmap.h>
0017 #include <linux/regulator/driver.h>
0018
0019 #define MT6360_PMU_CHG_CTRL1 0x311
0020 #define MT6360_PMU_CHG_CTRL2 0x312
0021 #define MT6360_PMU_CHG_CTRL3 0x313
0022 #define MT6360_PMU_CHG_CTRL4 0x314
0023 #define MT6360_PMU_CHG_CTRL5 0x315
0024 #define MT6360_PMU_CHG_CTRL6 0x316
0025 #define MT6360_PMU_CHG_CTRL7 0x317
0026 #define MT6360_PMU_CHG_CTRL8 0x318
0027 #define MT6360_PMU_CHG_CTRL9 0x319
0028 #define MT6360_PMU_CHG_CTRL10 0x31A
0029 #define MT6360_PMU_DEVICE_TYPE 0x322
0030 #define MT6360_PMU_USB_STATUS1 0x327
0031 #define MT6360_PMU_CHG_STAT 0x34A
0032 #define MT6360_PMU_CHG_CTRL19 0x361
0033 #define MT6360_PMU_FOD_STAT 0x3E7
0034
0035
0036 #define MT6360_FSLP_SHFT (3)
0037 #define MT6360_FSLP_MASK BIT(MT6360_FSLP_SHFT)
0038 #define MT6360_OPA_MODE_SHFT (0)
0039 #define MT6360_OPA_MODE_MASK BIT(MT6360_OPA_MODE_SHFT)
0040
0041 #define MT6360_IINLMTSEL_SHFT (2)
0042 #define MT6360_IINLMTSEL_MASK GENMASK(3, 2)
0043
0044 #define MT6360_IAICR_SHFT (2)
0045 #define MT6360_IAICR_MASK GENMASK(7, 2)
0046 #define MT6360_ILIM_EN_MASK BIT(0)
0047
0048 #define MT6360_VOREG_SHFT (1)
0049 #define MT6360_VOREG_MASK GENMASK(7, 1)
0050
0051 #define MT6360_VOBST_MASK GENMASK(7, 2)
0052
0053 #define MT6360_VMIVR_SHFT (1)
0054 #define MT6360_VMIVR_MASK GENMASK(7, 1)
0055
0056 #define MT6360_ICHG_SHFT (2)
0057 #define MT6360_ICHG_MASK GENMASK(7, 2)
0058
0059 #define MT6360_IPREC_SHFT (0)
0060 #define MT6360_IPREC_MASK GENMASK(3, 0)
0061
0062 #define MT6360_IEOC_SHFT (4)
0063 #define MT6360_IEOC_MASK GENMASK(7, 4)
0064
0065 #define MT6360_OTG_OC_MASK GENMASK(3, 0)
0066
0067 #define MT6360_USBCHGEN_MASK BIT(7)
0068
0069 #define MT6360_USB_STATUS_SHFT (4)
0070 #define MT6360_USB_STATUS_MASK GENMASK(6, 4)
0071
0072 #define MT6360_CHG_STAT_SHFT (6)
0073 #define MT6360_CHG_STAT_MASK GENMASK(7, 6)
0074 #define MT6360_VBAT_LVL_MASK BIT(5)
0075
0076 #define MT6360_VINOVP_SHFT (5)
0077 #define MT6360_VINOVP_MASK GENMASK(6, 5)
0078
0079 #define MT6360_CHRDET_EXT_MASK BIT(4)
0080
0081
0082 #define MT6360_VMIVR_MIN 3900000
0083 #define MT6360_VMIVR_MAX 13400000
0084 #define MT6360_VMIVR_STEP 100000
0085
0086 #define MT6360_ICHG_MIN 100000
0087 #define MT6360_ICHG_MAX 5000000
0088 #define MT6360_ICHG_STEP 100000
0089
0090 #define MT6360_VOREG_MIN 3900000
0091 #define MT6360_VOREG_MAX 4710000
0092 #define MT6360_VOREG_STEP 10000
0093
0094 #define MT6360_AICR_MIN 100000
0095 #define MT6360_AICR_MAX 3250000
0096 #define MT6360_AICR_STEP 50000
0097
0098 #define MT6360_IPREC_MIN 100000
0099 #define MT6360_IPREC_MAX 850000
0100 #define MT6360_IPREC_STEP 50000
0101
0102 #define MT6360_IEOC_MIN 100000
0103 #define MT6360_IEOC_MAX 850000
0104 #define MT6360_IEOC_STEP 50000
0105
0106 enum {
0107 MT6360_RANGE_VMIVR,
0108 MT6360_RANGE_ICHG,
0109 MT6360_RANGE_VOREG,
0110 MT6360_RANGE_AICR,
0111 MT6360_RANGE_IPREC,
0112 MT6360_RANGE_IEOC,
0113 MT6360_RANGE_MAX,
0114 };
0115
0116 #define MT6360_LINEAR_RANGE(idx, _min, _min_sel, _max_sel, _step) \
0117 [idx] = REGULATOR_LINEAR_RANGE(_min, _min_sel, _max_sel, _step)
0118
0119 static const struct linear_range mt6360_chg_range[MT6360_RANGE_MAX] = {
0120 MT6360_LINEAR_RANGE(MT6360_RANGE_VMIVR, 3900000, 0, 0x5F, 100000),
0121 MT6360_LINEAR_RANGE(MT6360_RANGE_ICHG, 100000, 0, 0x31, 100000),
0122 MT6360_LINEAR_RANGE(MT6360_RANGE_VOREG, 3900000, 0, 0x51, 10000),
0123 MT6360_LINEAR_RANGE(MT6360_RANGE_AICR, 100000, 0, 0x3F, 50000),
0124 MT6360_LINEAR_RANGE(MT6360_RANGE_IPREC, 100000, 0, 0x0F, 50000),
0125 MT6360_LINEAR_RANGE(MT6360_RANGE_IEOC, 100000, 0, 0x0F, 50000),
0126 };
0127
0128 struct mt6360_chg_info {
0129 struct device *dev;
0130 struct regmap *regmap;
0131 struct power_supply_desc psy_desc;
0132 struct power_supply *psy;
0133 struct regulator_dev *otg_rdev;
0134 struct mutex chgdet_lock;
0135 u32 vinovp;
0136 bool pwr_rdy;
0137 bool bc12_en;
0138 int psy_usb_type;
0139 struct work_struct chrdet_work;
0140 };
0141
0142 enum mt6360_iinlmtsel {
0143 MT6360_IINLMTSEL_AICR_3250 = 0,
0144 MT6360_IINLMTSEL_CHG_TYPE,
0145 MT6360_IINLMTSEL_AICR,
0146 MT6360_IINLMTSEL_LOWER_LEVEL,
0147 };
0148
0149 enum mt6360_pmu_chg_type {
0150 MT6360_CHG_TYPE_NOVBUS = 0,
0151 MT6360_CHG_TYPE_UNDER_GOING,
0152 MT6360_CHG_TYPE_SDP,
0153 MT6360_CHG_TYPE_SDPNSTD,
0154 MT6360_CHG_TYPE_DCP,
0155 MT6360_CHG_TYPE_CDP,
0156 MT6360_CHG_TYPE_DISABLE_BC12,
0157 MT6360_CHG_TYPE_MAX,
0158 };
0159
0160 static enum power_supply_usb_type mt6360_charger_usb_types[] = {
0161 POWER_SUPPLY_USB_TYPE_UNKNOWN,
0162 POWER_SUPPLY_USB_TYPE_SDP,
0163 POWER_SUPPLY_USB_TYPE_DCP,
0164 POWER_SUPPLY_USB_TYPE_CDP,
0165 };
0166
0167 static int mt6360_get_chrdet_ext_stat(struct mt6360_chg_info *mci,
0168 bool *pwr_rdy)
0169 {
0170 int ret;
0171 unsigned int regval;
0172
0173 ret = regmap_read(mci->regmap, MT6360_PMU_FOD_STAT, ®val);
0174 if (ret < 0)
0175 return ret;
0176 *pwr_rdy = (regval & MT6360_CHRDET_EXT_MASK) ? true : false;
0177 return 0;
0178 }
0179
0180 static int mt6360_charger_get_online(struct mt6360_chg_info *mci,
0181 union power_supply_propval *val)
0182 {
0183 int ret;
0184 bool pwr_rdy;
0185
0186 ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
0187 if (ret < 0)
0188 return ret;
0189 val->intval = pwr_rdy ? true : false;
0190 return 0;
0191 }
0192
0193 static int mt6360_charger_get_status(struct mt6360_chg_info *mci,
0194 union power_supply_propval *val)
0195 {
0196 int status, ret;
0197 unsigned int regval;
0198 bool pwr_rdy;
0199
0200 ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
0201 if (ret < 0)
0202 return ret;
0203 if (!pwr_rdy) {
0204 status = POWER_SUPPLY_STATUS_DISCHARGING;
0205 goto out;
0206 }
0207
0208 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, ®val);
0209 if (ret < 0)
0210 return ret;
0211 regval &= MT6360_CHG_STAT_MASK;
0212 regval >>= MT6360_CHG_STAT_SHFT;
0213 switch (regval) {
0214 case 0x0:
0215 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
0216 break;
0217 case 0x1:
0218 status = POWER_SUPPLY_STATUS_CHARGING;
0219 break;
0220 case 0x2:
0221 status = POWER_SUPPLY_STATUS_FULL;
0222 break;
0223 default:
0224 ret = -EIO;
0225 }
0226 out:
0227 if (!ret)
0228 val->intval = status;
0229 return ret;
0230 }
0231
0232 static int mt6360_charger_get_charge_type(struct mt6360_chg_info *mci,
0233 union power_supply_propval *val)
0234 {
0235 int type, ret;
0236 unsigned int regval;
0237 u8 chg_stat;
0238
0239 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, ®val);
0240 if (ret < 0)
0241 return ret;
0242
0243 chg_stat = (regval & MT6360_CHG_STAT_MASK) >> MT6360_CHG_STAT_SHFT;
0244 switch (chg_stat) {
0245 case 0x01:
0246 if (regval & MT6360_VBAT_LVL_MASK)
0247 type = POWER_SUPPLY_CHARGE_TYPE_FAST;
0248 else
0249 type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0250 break;
0251 case 0x00:
0252 case 0x02:
0253 case 0x03:
0254 default:
0255 type = POWER_SUPPLY_CHARGE_TYPE_NONE;
0256 break;
0257 }
0258
0259 val->intval = type;
0260 return 0;
0261 }
0262
0263 static int mt6360_charger_get_ichg(struct mt6360_chg_info *mci,
0264 union power_supply_propval *val)
0265 {
0266 int ret;
0267 u32 sel, value;
0268
0269 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL7, &sel);
0270 if (ret < 0)
0271 return ret;
0272 sel = (sel & MT6360_ICHG_MASK) >> MT6360_ICHG_SHFT;
0273 ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_ICHG], sel, &value);
0274 if (!ret)
0275 val->intval = value;
0276 return ret;
0277 }
0278
0279 static int mt6360_charger_get_max_ichg(struct mt6360_chg_info *mci,
0280 union power_supply_propval *val)
0281 {
0282 val->intval = MT6360_ICHG_MAX;
0283 return 0;
0284 }
0285
0286 static int mt6360_charger_get_cv(struct mt6360_chg_info *mci,
0287 union power_supply_propval *val)
0288 {
0289 int ret;
0290 u32 sel, value;
0291
0292 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL4, &sel);
0293 if (ret < 0)
0294 return ret;
0295 sel = (sel & MT6360_VOREG_MASK) >> MT6360_VOREG_SHFT;
0296 ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VOREG], sel, &value);
0297 if (!ret)
0298 val->intval = value;
0299 return ret;
0300 }
0301
0302 static int mt6360_charger_get_max_cv(struct mt6360_chg_info *mci,
0303 union power_supply_propval *val)
0304 {
0305 val->intval = MT6360_VOREG_MAX;
0306 return 0;
0307 }
0308
0309 static int mt6360_charger_get_aicr(struct mt6360_chg_info *mci,
0310 union power_supply_propval *val)
0311 {
0312 int ret;
0313 u32 sel, value;
0314
0315 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL3, &sel);
0316 if (ret < 0)
0317 return ret;
0318 sel = (sel & MT6360_IAICR_MASK) >> MT6360_IAICR_SHFT;
0319 ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_AICR], sel, &value);
0320 if (!ret)
0321 val->intval = value;
0322 return ret;
0323 }
0324
0325 static int mt6360_charger_get_mivr(struct mt6360_chg_info *mci,
0326 union power_supply_propval *val)
0327 {
0328 int ret;
0329 u32 sel, value;
0330
0331 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL6, &sel);
0332 if (ret < 0)
0333 return ret;
0334 sel = (sel & MT6360_VMIVR_MASK) >> MT6360_VMIVR_SHFT;
0335 ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VMIVR], sel, &value);
0336 if (!ret)
0337 val->intval = value;
0338 return ret;
0339 }
0340
0341 static int mt6360_charger_get_iprechg(struct mt6360_chg_info *mci,
0342 union power_supply_propval *val)
0343 {
0344 int ret;
0345 u32 sel, value;
0346
0347 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL8, &sel);
0348 if (ret < 0)
0349 return ret;
0350 sel = (sel & MT6360_IPREC_MASK) >> MT6360_IPREC_SHFT;
0351 ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IPREC], sel, &value);
0352 if (!ret)
0353 val->intval = value;
0354 return ret;
0355 }
0356
0357 static int mt6360_charger_get_ieoc(struct mt6360_chg_info *mci,
0358 union power_supply_propval *val)
0359 {
0360 int ret;
0361 u32 sel, value;
0362
0363 ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL9, &sel);
0364 if (ret < 0)
0365 return ret;
0366 sel = (sel & MT6360_IEOC_MASK) >> MT6360_IEOC_SHFT;
0367 ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IEOC], sel, &value);
0368 if (!ret)
0369 val->intval = value;
0370 return ret;
0371 }
0372
0373 static int mt6360_charger_set_online(struct mt6360_chg_info *mci,
0374 const union power_supply_propval *val)
0375 {
0376 u8 force_sleep = val->intval ? 0 : 1;
0377
0378 return regmap_update_bits(mci->regmap,
0379 MT6360_PMU_CHG_CTRL1,
0380 MT6360_FSLP_MASK,
0381 force_sleep << MT6360_FSLP_SHFT);
0382 }
0383
0384 static int mt6360_charger_set_ichg(struct mt6360_chg_info *mci,
0385 const union power_supply_propval *val)
0386 {
0387 u32 sel;
0388
0389 linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_ICHG], val->intval, &sel);
0390 return regmap_update_bits(mci->regmap,
0391 MT6360_PMU_CHG_CTRL7,
0392 MT6360_ICHG_MASK,
0393 sel << MT6360_ICHG_SHFT);
0394 }
0395
0396 static int mt6360_charger_set_cv(struct mt6360_chg_info *mci,
0397 const union power_supply_propval *val)
0398 {
0399 u32 sel;
0400
0401 linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VOREG], val->intval, &sel);
0402 return regmap_update_bits(mci->regmap,
0403 MT6360_PMU_CHG_CTRL4,
0404 MT6360_VOREG_MASK,
0405 sel << MT6360_VOREG_SHFT);
0406 }
0407
0408 static int mt6360_charger_set_aicr(struct mt6360_chg_info *mci,
0409 const union power_supply_propval *val)
0410 {
0411 u32 sel;
0412
0413 linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_AICR], val->intval, &sel);
0414 return regmap_update_bits(mci->regmap,
0415 MT6360_PMU_CHG_CTRL3,
0416 MT6360_IAICR_MASK,
0417 sel << MT6360_IAICR_SHFT);
0418 }
0419
0420 static int mt6360_charger_set_mivr(struct mt6360_chg_info *mci,
0421 const union power_supply_propval *val)
0422 {
0423 u32 sel;
0424
0425 linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VMIVR], val->intval, &sel);
0426 return regmap_update_bits(mci->regmap,
0427 MT6360_PMU_CHG_CTRL3,
0428 MT6360_VMIVR_MASK,
0429 sel << MT6360_VMIVR_SHFT);
0430 }
0431
0432 static int mt6360_charger_set_iprechg(struct mt6360_chg_info *mci,
0433 const union power_supply_propval *val)
0434 {
0435 u32 sel;
0436
0437 linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IPREC], val->intval, &sel);
0438 return regmap_update_bits(mci->regmap,
0439 MT6360_PMU_CHG_CTRL8,
0440 MT6360_IPREC_MASK,
0441 sel << MT6360_IPREC_SHFT);
0442 }
0443
0444 static int mt6360_charger_set_ieoc(struct mt6360_chg_info *mci,
0445 const union power_supply_propval *val)
0446 {
0447 u32 sel;
0448
0449 linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IEOC], val->intval, &sel);
0450 return regmap_update_bits(mci->regmap,
0451 MT6360_PMU_CHG_CTRL9,
0452 MT6360_IEOC_MASK,
0453 sel << MT6360_IEOC_SHFT);
0454 }
0455
0456 static int mt6360_charger_get_property(struct power_supply *psy,
0457 enum power_supply_property psp,
0458 union power_supply_propval *val)
0459 {
0460 struct mt6360_chg_info *mci = power_supply_get_drvdata(psy);
0461 int ret = 0;
0462
0463 switch (psp) {
0464 case POWER_SUPPLY_PROP_ONLINE:
0465 ret = mt6360_charger_get_online(mci, val);
0466 break;
0467 case POWER_SUPPLY_PROP_STATUS:
0468 ret = mt6360_charger_get_status(mci, val);
0469 break;
0470 case POWER_SUPPLY_PROP_CHARGE_TYPE:
0471 ret = mt6360_charger_get_charge_type(mci, val);
0472 break;
0473 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
0474 ret = mt6360_charger_get_ichg(mci, val);
0475 break;
0476 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
0477 ret = mt6360_charger_get_max_ichg(mci, val);
0478 break;
0479 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
0480 ret = mt6360_charger_get_cv(mci, val);
0481 break;
0482 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
0483 ret = mt6360_charger_get_max_cv(mci, val);
0484 break;
0485 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0486 ret = mt6360_charger_get_aicr(mci, val);
0487 break;
0488 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
0489 ret = mt6360_charger_get_mivr(mci, val);
0490 break;
0491 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
0492 ret = mt6360_charger_get_iprechg(mci, val);
0493 break;
0494 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0495 ret = mt6360_charger_get_ieoc(mci, val);
0496 break;
0497 case POWER_SUPPLY_PROP_USB_TYPE:
0498 val->intval = mci->psy_usb_type;
0499 break;
0500 default:
0501 ret = -ENODATA;
0502 }
0503 return ret;
0504 }
0505
0506 static int mt6360_charger_set_property(struct power_supply *psy,
0507 enum power_supply_property psp,
0508 const union power_supply_propval *val)
0509 {
0510 struct mt6360_chg_info *mci = power_supply_get_drvdata(psy);
0511 int ret;
0512
0513 switch (psp) {
0514 case POWER_SUPPLY_PROP_ONLINE:
0515 ret = mt6360_charger_set_online(mci, val);
0516 break;
0517 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
0518 ret = mt6360_charger_set_ichg(mci, val);
0519 break;
0520 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
0521 ret = mt6360_charger_set_cv(mci, val);
0522 break;
0523 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0524 ret = mt6360_charger_set_aicr(mci, val);
0525 break;
0526 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
0527 ret = mt6360_charger_set_mivr(mci, val);
0528 break;
0529 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
0530 ret = mt6360_charger_set_iprechg(mci, val);
0531 break;
0532 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0533 ret = mt6360_charger_set_ieoc(mci, val);
0534 break;
0535 default:
0536 ret = -EINVAL;
0537 }
0538 return ret;
0539 }
0540
0541 static int mt6360_charger_property_is_writeable(struct power_supply *psy,
0542 enum power_supply_property psp)
0543 {
0544 switch (psp) {
0545 case POWER_SUPPLY_PROP_ONLINE:
0546 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
0547 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
0548 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0549 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
0550 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
0551 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0552 return 1;
0553 default:
0554 return 0;
0555 }
0556 }
0557
0558 static enum power_supply_property mt6360_charger_properties[] = {
0559 POWER_SUPPLY_PROP_ONLINE,
0560 POWER_SUPPLY_PROP_STATUS,
0561 POWER_SUPPLY_PROP_CHARGE_TYPE,
0562 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
0563 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
0564 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
0565 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
0566 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
0567 POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
0568 POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
0569 POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
0570 POWER_SUPPLY_PROP_USB_TYPE,
0571 };
0572
0573 static const struct power_supply_desc mt6360_charger_desc = {
0574 .type = POWER_SUPPLY_TYPE_USB,
0575 .properties = mt6360_charger_properties,
0576 .num_properties = ARRAY_SIZE(mt6360_charger_properties),
0577 .get_property = mt6360_charger_get_property,
0578 .set_property = mt6360_charger_set_property,
0579 .property_is_writeable = mt6360_charger_property_is_writeable,
0580 .usb_types = mt6360_charger_usb_types,
0581 .num_usb_types = ARRAY_SIZE(mt6360_charger_usb_types),
0582 };
0583
0584 static const struct regulator_ops mt6360_chg_otg_ops = {
0585 .list_voltage = regulator_list_voltage_linear,
0586 .enable = regulator_enable_regmap,
0587 .disable = regulator_disable_regmap,
0588 .is_enabled = regulator_is_enabled_regmap,
0589 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0590 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0591 };
0592
0593 static const struct regulator_desc mt6360_otg_rdesc = {
0594 .of_match = "usb-otg-vbus",
0595 .name = "usb-otg-vbus",
0596 .ops = &mt6360_chg_otg_ops,
0597 .owner = THIS_MODULE,
0598 .type = REGULATOR_VOLTAGE,
0599 .min_uV = 4425000,
0600 .uV_step = 25000,
0601 .n_voltages = 57,
0602 .vsel_reg = MT6360_PMU_CHG_CTRL5,
0603 .vsel_mask = MT6360_VOBST_MASK,
0604 .enable_reg = MT6360_PMU_CHG_CTRL1,
0605 .enable_mask = MT6360_OPA_MODE_MASK,
0606 };
0607
0608 static irqreturn_t mt6360_pmu_attach_i_handler(int irq, void *data)
0609 {
0610 struct mt6360_chg_info *mci = data;
0611 int ret;
0612 unsigned int usb_status;
0613 int last_usb_type;
0614
0615 mutex_lock(&mci->chgdet_lock);
0616 if (!mci->bc12_en) {
0617 dev_warn(mci->dev, "Received attach interrupt, bc12 disabled, ignore irq\n");
0618 goto out;
0619 }
0620 last_usb_type = mci->psy_usb_type;
0621
0622 ret = regmap_read(mci->regmap, MT6360_PMU_USB_STATUS1, &usb_status);
0623 if (ret < 0)
0624 goto out;
0625 usb_status &= MT6360_USB_STATUS_MASK;
0626 usb_status >>= MT6360_USB_STATUS_SHFT;
0627 switch (usb_status) {
0628 case MT6360_CHG_TYPE_NOVBUS:
0629 dev_dbg(mci->dev, "Received attach interrupt, no vbus\n");
0630 goto out;
0631 case MT6360_CHG_TYPE_UNDER_GOING:
0632 dev_dbg(mci->dev, "Received attach interrupt, under going...\n");
0633 goto out;
0634 case MT6360_CHG_TYPE_SDP:
0635 mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
0636 break;
0637 case MT6360_CHG_TYPE_SDPNSTD:
0638 mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
0639 break;
0640 case MT6360_CHG_TYPE_CDP:
0641 mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;
0642 break;
0643 case MT6360_CHG_TYPE_DCP:
0644 mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
0645 break;
0646 case MT6360_CHG_TYPE_DISABLE_BC12:
0647 dev_dbg(mci->dev, "Received attach interrupt, bc12 detect not enable\n");
0648 goto out;
0649 default:
0650 mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
0651 dev_dbg(mci->dev, "Received attach interrupt, reserved address\n");
0652 goto out;
0653 }
0654
0655 dev_dbg(mci->dev, "Received attach interrupt, chg_type = %d\n", mci->psy_usb_type);
0656 if (last_usb_type != mci->psy_usb_type)
0657 power_supply_changed(mci->psy);
0658 out:
0659 mutex_unlock(&mci->chgdet_lock);
0660 return IRQ_HANDLED;
0661 }
0662
0663 static void mt6360_handle_chrdet_ext_evt(struct mt6360_chg_info *mci)
0664 {
0665 int ret;
0666 bool pwr_rdy;
0667
0668 mutex_lock(&mci->chgdet_lock);
0669 ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
0670 if (ret < 0)
0671 goto out;
0672 if (mci->pwr_rdy == pwr_rdy) {
0673 dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy is same(%d)\n", pwr_rdy);
0674 goto out;
0675 }
0676 mci->pwr_rdy = pwr_rdy;
0677 dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy = %d\n", pwr_rdy);
0678 if (!pwr_rdy) {
0679 mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
0680 power_supply_changed(mci->psy);
0681
0682 }
0683 ret = regmap_update_bits(mci->regmap,
0684 MT6360_PMU_DEVICE_TYPE,
0685 MT6360_USBCHGEN_MASK,
0686 pwr_rdy ? MT6360_USBCHGEN_MASK : 0);
0687 if (ret < 0)
0688 goto out;
0689 mci->bc12_en = pwr_rdy;
0690 out:
0691 mutex_unlock(&mci->chgdet_lock);
0692 }
0693
0694 static void mt6360_chrdet_work(struct work_struct *work)
0695 {
0696 struct mt6360_chg_info *mci = (struct mt6360_chg_info *)container_of(
0697 work, struct mt6360_chg_info, chrdet_work);
0698
0699 mt6360_handle_chrdet_ext_evt(mci);
0700 }
0701
0702 static irqreturn_t mt6360_pmu_chrdet_ext_evt_handler(int irq, void *data)
0703 {
0704 struct mt6360_chg_info *mci = data;
0705
0706 mt6360_handle_chrdet_ext_evt(mci);
0707 return IRQ_HANDLED;
0708 }
0709
0710 static int mt6360_chg_irq_register(struct platform_device *pdev)
0711 {
0712 const struct {
0713 const char *name;
0714 irq_handler_t handler;
0715 } irq_descs[] = {
0716 { "attach_i", mt6360_pmu_attach_i_handler },
0717 { "chrdet_ext_evt", mt6360_pmu_chrdet_ext_evt_handler }
0718 };
0719 int i, ret;
0720
0721 for (i = 0; i < ARRAY_SIZE(irq_descs); i++) {
0722 ret = platform_get_irq_byname(pdev, irq_descs[i].name);
0723 if (ret < 0)
0724 return ret;
0725
0726 ret = devm_request_threaded_irq(&pdev->dev, ret, NULL,
0727 irq_descs[i].handler,
0728 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
0729 irq_descs[i].name,
0730 platform_get_drvdata(pdev));
0731 if (ret < 0)
0732 return dev_err_probe(&pdev->dev, ret, "Failed to request %s irq\n",
0733 irq_descs[i].name);
0734 }
0735
0736 return 0;
0737 }
0738
0739 static u32 mt6360_vinovp_trans_to_sel(u32 val)
0740 {
0741 u32 vinovp_tbl[] = { 5500000, 6500000, 11000000, 14500000 };
0742 int i;
0743
0744
0745 for (i = 0; i < ARRAY_SIZE(vinovp_tbl)-1; i++) {
0746 if (val < vinovp_tbl[i+1])
0747 break;
0748 }
0749 return i;
0750 }
0751
0752 static int mt6360_chg_init_setting(struct mt6360_chg_info *mci)
0753 {
0754 int ret;
0755 u32 sel;
0756
0757 sel = mt6360_vinovp_trans_to_sel(mci->vinovp);
0758 ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL19,
0759 MT6360_VINOVP_MASK, sel << MT6360_VINOVP_SHFT);
0760 if (ret)
0761 return dev_err_probe(mci->dev, ret, "%s: Failed to apply vinovp\n", __func__);
0762 ret = regmap_update_bits(mci->regmap, MT6360_PMU_DEVICE_TYPE,
0763 MT6360_USBCHGEN_MASK, 0);
0764 if (ret)
0765 return dev_err_probe(mci->dev, ret, "%s: Failed to disable bc12\n", __func__);
0766 ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL2,
0767 MT6360_IINLMTSEL_MASK,
0768 MT6360_IINLMTSEL_AICR <<
0769 MT6360_IINLMTSEL_SHFT);
0770 if (ret)
0771 return dev_err_probe(mci->dev, ret,
0772 "%s: Failed to switch iinlmtsel to aicr\n", __func__);
0773 usleep_range(5000, 6000);
0774 ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL3,
0775 MT6360_ILIM_EN_MASK, 0);
0776 if (ret)
0777 return dev_err_probe(mci->dev, ret,
0778 "%s: Failed to disable ilim\n", __func__);
0779 ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL10,
0780 MT6360_OTG_OC_MASK, MT6360_OTG_OC_MASK);
0781 if (ret)
0782 return dev_err_probe(mci->dev, ret,
0783 "%s: Failed to config otg oc to 3A\n", __func__);
0784 return 0;
0785 }
0786
0787 static int mt6360_charger_probe(struct platform_device *pdev)
0788 {
0789 struct mt6360_chg_info *mci;
0790 struct power_supply_config charger_cfg = {};
0791 struct regulator_config config = { };
0792 int ret;
0793
0794 mci = devm_kzalloc(&pdev->dev, sizeof(*mci), GFP_KERNEL);
0795 if (!mci)
0796 return -ENOMEM;
0797
0798 mci->dev = &pdev->dev;
0799 mci->vinovp = 6500000;
0800 mutex_init(&mci->chgdet_lock);
0801 platform_set_drvdata(pdev, mci);
0802 devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work);
0803
0804 ret = device_property_read_u32(&pdev->dev, "richtek,vinovp-microvolt", &mci->vinovp);
0805 if (ret)
0806 dev_warn(&pdev->dev, "Failed to parse vinovp in DT, keep default 6.5v\n");
0807
0808 mci->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0809 if (!mci->regmap)
0810 return dev_err_probe(&pdev->dev, -ENODEV, "Failed to get parent regmap\n");
0811
0812 ret = mt6360_chg_init_setting(mci);
0813 if (ret)
0814 return dev_err_probe(&pdev->dev, ret, "Failed to initial setting\n");
0815
0816 memcpy(&mci->psy_desc, &mt6360_charger_desc, sizeof(mci->psy_desc));
0817 mci->psy_desc.name = dev_name(&pdev->dev);
0818 charger_cfg.drv_data = mci;
0819 charger_cfg.of_node = pdev->dev.of_node;
0820 mci->psy = devm_power_supply_register(&pdev->dev,
0821 &mci->psy_desc, &charger_cfg);
0822 if (IS_ERR(mci->psy))
0823 return dev_err_probe(&pdev->dev, PTR_ERR(mci->psy),
0824 "Failed to register power supply dev\n");
0825
0826
0827 ret = mt6360_chg_irq_register(pdev);
0828 if (ret)
0829 return dev_err_probe(&pdev->dev, ret, "Failed to register irqs\n");
0830
0831 config.dev = &pdev->dev;
0832 config.regmap = mci->regmap;
0833 mci->otg_rdev = devm_regulator_register(&pdev->dev, &mt6360_otg_rdesc,
0834 &config);
0835 if (IS_ERR(mci->otg_rdev))
0836 return PTR_ERR(mci->otg_rdev);
0837
0838 schedule_work(&mci->chrdet_work);
0839
0840 return 0;
0841 }
0842
0843 static const struct of_device_id __maybe_unused mt6360_charger_of_id[] = {
0844 { .compatible = "mediatek,mt6360-chg", },
0845 {},
0846 };
0847 MODULE_DEVICE_TABLE(of, mt6360_charger_of_id);
0848
0849 static const struct platform_device_id mt6360_charger_id[] = {
0850 { "mt6360-chg", 0 },
0851 {},
0852 };
0853 MODULE_DEVICE_TABLE(platform, mt6360_charger_id);
0854
0855 static struct platform_driver mt6360_charger_driver = {
0856 .driver = {
0857 .name = "mt6360-chg",
0858 .of_match_table = of_match_ptr(mt6360_charger_of_id),
0859 },
0860 .probe = mt6360_charger_probe,
0861 .id_table = mt6360_charger_id,
0862 };
0863 module_platform_driver(mt6360_charger_driver);
0864
0865 MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>");
0866 MODULE_DESCRIPTION("MT6360 Charger Driver");
0867 MODULE_LICENSE("GPL");