Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2021 MediaTek Inc.
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 /* MT6360_PMU_CHG_CTRL1 */
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 /* MT6360_PMU_CHG_CTRL2 */
0041 #define MT6360_IINLMTSEL_SHFT   (2)
0042 #define MT6360_IINLMTSEL_MASK   GENMASK(3, 2)
0043 /* MT6360_PMU_CHG_CTRL3 */
0044 #define MT6360_IAICR_SHFT   (2)
0045 #define MT6360_IAICR_MASK   GENMASK(7, 2)
0046 #define MT6360_ILIM_EN_MASK BIT(0)
0047 /* MT6360_PMU_CHG_CTRL4 */
0048 #define MT6360_VOREG_SHFT   (1)
0049 #define MT6360_VOREG_MASK   GENMASK(7, 1)
0050 /* MT6360_PMU_CHG_CTRL5 */
0051 #define MT6360_VOBST_MASK   GENMASK(7, 2)
0052 /* MT6360_PMU_CHG_CTRL6 */
0053 #define MT6360_VMIVR_SHFT      (1)
0054 #define MT6360_VMIVR_MASK      GENMASK(7, 1)
0055 /* MT6360_PMU_CHG_CTRL7 */
0056 #define MT6360_ICHG_SHFT    (2)
0057 #define MT6360_ICHG_MASK    GENMASK(7, 2)
0058 /* MT6360_PMU_CHG_CTRL8 */
0059 #define MT6360_IPREC_SHFT   (0)
0060 #define MT6360_IPREC_MASK   GENMASK(3, 0)
0061 /* MT6360_PMU_CHG_CTRL9 */
0062 #define MT6360_IEOC_SHFT    (4)
0063 #define MT6360_IEOC_MASK    GENMASK(7, 4)
0064 /* MT6360_PMU_CHG_CTRL10 */
0065 #define MT6360_OTG_OC_MASK  GENMASK(3, 0)
0066 /* MT6360_PMU_DEVICE_TYPE */
0067 #define MT6360_USBCHGEN_MASK    BIT(7)
0068 /* MT6360_PMU_USB_STATUS1 */
0069 #define MT6360_USB_STATUS_SHFT  (4)
0070 #define MT6360_USB_STATUS_MASK  GENMASK(6, 4)
0071 /* MT6360_PMU_CHG_STAT */
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 /* MT6360_PMU_CHG_CTRL19 */
0076 #define MT6360_VINOVP_SHFT  (5)
0077 #define MT6360_VINOVP_MASK  GENMASK(6, 5)
0078 /* MT6360_PMU_FOD_STAT */
0079 #define MT6360_CHRDET_EXT_MASK  BIT(4)
0080 
0081 /* uV */
0082 #define MT6360_VMIVR_MIN    3900000
0083 #define MT6360_VMIVR_MAX    13400000
0084 #define MT6360_VMIVR_STEP   100000
0085 /* uA */
0086 #define MT6360_ICHG_MIN     100000
0087 #define MT6360_ICHG_MAX     5000000
0088 #define MT6360_ICHG_STEP    100000
0089 /* uV */
0090 #define MT6360_VOREG_MIN    3900000
0091 #define MT6360_VOREG_MAX    4710000
0092 #define MT6360_VOREG_STEP   10000
0093 /* uA */
0094 #define MT6360_AICR_MIN     100000
0095 #define MT6360_AICR_MAX     3250000
0096 #define MT6360_AICR_STEP    50000
0097 /* uA */
0098 #define MT6360_IPREC_MIN    100000
0099 #define MT6360_IPREC_MAX    850000
0100 #define MT6360_IPREC_STEP   50000
0101 /* uA */
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, &regval);
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, &regval);
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, &regval);
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: /* Charge in Progress */
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: /* Not Charging */
0252     case 0x02: /* Charge Done */
0253     case 0x03: /* Charge Fault */
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     /* Plug in */
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     /* Select the smaller and equal supported value */
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");