162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2021 MediaTek Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/devm-helpers.h> 762306a36Sopenharmony_ci#include <linux/init.h> 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/linear_range.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/power_supply.h> 1562306a36Sopenharmony_ci#include <linux/property.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL1 0x311 2062306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL2 0x312 2162306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL3 0x313 2262306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL4 0x314 2362306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL5 0x315 2462306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL6 0x316 2562306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL7 0x317 2662306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL8 0x318 2762306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL9 0x319 2862306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL10 0x31A 2962306a36Sopenharmony_ci#define MT6360_PMU_DEVICE_TYPE 0x322 3062306a36Sopenharmony_ci#define MT6360_PMU_USB_STATUS1 0x327 3162306a36Sopenharmony_ci#define MT6360_PMU_CHG_STAT 0x34A 3262306a36Sopenharmony_ci#define MT6360_PMU_CHG_CTRL19 0x361 3362306a36Sopenharmony_ci#define MT6360_PMU_FOD_STAT 0x3E7 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL1 */ 3662306a36Sopenharmony_ci#define MT6360_FSLP_SHFT (3) 3762306a36Sopenharmony_ci#define MT6360_FSLP_MASK BIT(MT6360_FSLP_SHFT) 3862306a36Sopenharmony_ci#define MT6360_OPA_MODE_SHFT (0) 3962306a36Sopenharmony_ci#define MT6360_OPA_MODE_MASK BIT(MT6360_OPA_MODE_SHFT) 4062306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL2 */ 4162306a36Sopenharmony_ci#define MT6360_IINLMTSEL_SHFT (2) 4262306a36Sopenharmony_ci#define MT6360_IINLMTSEL_MASK GENMASK(3, 2) 4362306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL3 */ 4462306a36Sopenharmony_ci#define MT6360_IAICR_SHFT (2) 4562306a36Sopenharmony_ci#define MT6360_IAICR_MASK GENMASK(7, 2) 4662306a36Sopenharmony_ci#define MT6360_ILIM_EN_MASK BIT(0) 4762306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL4 */ 4862306a36Sopenharmony_ci#define MT6360_VOREG_SHFT (1) 4962306a36Sopenharmony_ci#define MT6360_VOREG_MASK GENMASK(7, 1) 5062306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL5 */ 5162306a36Sopenharmony_ci#define MT6360_VOBST_MASK GENMASK(7, 2) 5262306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL6 */ 5362306a36Sopenharmony_ci#define MT6360_VMIVR_SHFT (1) 5462306a36Sopenharmony_ci#define MT6360_VMIVR_MASK GENMASK(7, 1) 5562306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL7 */ 5662306a36Sopenharmony_ci#define MT6360_ICHG_SHFT (2) 5762306a36Sopenharmony_ci#define MT6360_ICHG_MASK GENMASK(7, 2) 5862306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL8 */ 5962306a36Sopenharmony_ci#define MT6360_IPREC_SHFT (0) 6062306a36Sopenharmony_ci#define MT6360_IPREC_MASK GENMASK(3, 0) 6162306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL9 */ 6262306a36Sopenharmony_ci#define MT6360_IEOC_SHFT (4) 6362306a36Sopenharmony_ci#define MT6360_IEOC_MASK GENMASK(7, 4) 6462306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL10 */ 6562306a36Sopenharmony_ci#define MT6360_OTG_OC_MASK GENMASK(3, 0) 6662306a36Sopenharmony_ci/* MT6360_PMU_DEVICE_TYPE */ 6762306a36Sopenharmony_ci#define MT6360_USBCHGEN_MASK BIT(7) 6862306a36Sopenharmony_ci/* MT6360_PMU_USB_STATUS1 */ 6962306a36Sopenharmony_ci#define MT6360_USB_STATUS_SHFT (4) 7062306a36Sopenharmony_ci#define MT6360_USB_STATUS_MASK GENMASK(6, 4) 7162306a36Sopenharmony_ci/* MT6360_PMU_CHG_STAT */ 7262306a36Sopenharmony_ci#define MT6360_CHG_STAT_SHFT (6) 7362306a36Sopenharmony_ci#define MT6360_CHG_STAT_MASK GENMASK(7, 6) 7462306a36Sopenharmony_ci#define MT6360_VBAT_LVL_MASK BIT(5) 7562306a36Sopenharmony_ci/* MT6360_PMU_CHG_CTRL19 */ 7662306a36Sopenharmony_ci#define MT6360_VINOVP_SHFT (5) 7762306a36Sopenharmony_ci#define MT6360_VINOVP_MASK GENMASK(6, 5) 7862306a36Sopenharmony_ci/* MT6360_PMU_FOD_STAT */ 7962306a36Sopenharmony_ci#define MT6360_CHRDET_EXT_MASK BIT(4) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* uV */ 8262306a36Sopenharmony_ci#define MT6360_VMIVR_MIN 3900000 8362306a36Sopenharmony_ci#define MT6360_VMIVR_MAX 13400000 8462306a36Sopenharmony_ci#define MT6360_VMIVR_STEP 100000 8562306a36Sopenharmony_ci/* uA */ 8662306a36Sopenharmony_ci#define MT6360_ICHG_MIN 100000 8762306a36Sopenharmony_ci#define MT6360_ICHG_MAX 5000000 8862306a36Sopenharmony_ci#define MT6360_ICHG_STEP 100000 8962306a36Sopenharmony_ci/* uV */ 9062306a36Sopenharmony_ci#define MT6360_VOREG_MIN 3900000 9162306a36Sopenharmony_ci#define MT6360_VOREG_MAX 4710000 9262306a36Sopenharmony_ci#define MT6360_VOREG_STEP 10000 9362306a36Sopenharmony_ci/* uA */ 9462306a36Sopenharmony_ci#define MT6360_AICR_MIN 100000 9562306a36Sopenharmony_ci#define MT6360_AICR_MAX 3250000 9662306a36Sopenharmony_ci#define MT6360_AICR_STEP 50000 9762306a36Sopenharmony_ci/* uA */ 9862306a36Sopenharmony_ci#define MT6360_IPREC_MIN 100000 9962306a36Sopenharmony_ci#define MT6360_IPREC_MAX 850000 10062306a36Sopenharmony_ci#define MT6360_IPREC_STEP 50000 10162306a36Sopenharmony_ci/* uA */ 10262306a36Sopenharmony_ci#define MT6360_IEOC_MIN 100000 10362306a36Sopenharmony_ci#define MT6360_IEOC_MAX 850000 10462306a36Sopenharmony_ci#define MT6360_IEOC_STEP 50000 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cienum { 10762306a36Sopenharmony_ci MT6360_RANGE_VMIVR, 10862306a36Sopenharmony_ci MT6360_RANGE_ICHG, 10962306a36Sopenharmony_ci MT6360_RANGE_VOREG, 11062306a36Sopenharmony_ci MT6360_RANGE_AICR, 11162306a36Sopenharmony_ci MT6360_RANGE_IPREC, 11262306a36Sopenharmony_ci MT6360_RANGE_IEOC, 11362306a36Sopenharmony_ci MT6360_RANGE_MAX, 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic const struct linear_range mt6360_chg_range[MT6360_RANGE_MAX] = { 11762306a36Sopenharmony_ci LINEAR_RANGE_IDX(MT6360_RANGE_VMIVR, 3900000, 0, 0x5F, 100000), 11862306a36Sopenharmony_ci LINEAR_RANGE_IDX(MT6360_RANGE_ICHG, 100000, 0, 0x31, 100000), 11962306a36Sopenharmony_ci LINEAR_RANGE_IDX(MT6360_RANGE_VOREG, 3900000, 0, 0x51, 10000), 12062306a36Sopenharmony_ci LINEAR_RANGE_IDX(MT6360_RANGE_AICR, 100000, 0, 0x3F, 50000), 12162306a36Sopenharmony_ci LINEAR_RANGE_IDX(MT6360_RANGE_IPREC, 100000, 0, 0x0F, 50000), 12262306a36Sopenharmony_ci LINEAR_RANGE_IDX(MT6360_RANGE_IEOC, 100000, 0, 0x0F, 50000), 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistruct mt6360_chg_info { 12662306a36Sopenharmony_ci struct device *dev; 12762306a36Sopenharmony_ci struct regmap *regmap; 12862306a36Sopenharmony_ci struct power_supply_desc psy_desc; 12962306a36Sopenharmony_ci struct power_supply *psy; 13062306a36Sopenharmony_ci struct regulator_dev *otg_rdev; 13162306a36Sopenharmony_ci struct mutex chgdet_lock; 13262306a36Sopenharmony_ci u32 vinovp; 13362306a36Sopenharmony_ci bool pwr_rdy; 13462306a36Sopenharmony_ci bool bc12_en; 13562306a36Sopenharmony_ci int psy_usb_type; 13662306a36Sopenharmony_ci struct work_struct chrdet_work; 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cienum mt6360_iinlmtsel { 14062306a36Sopenharmony_ci MT6360_IINLMTSEL_AICR_3250 = 0, 14162306a36Sopenharmony_ci MT6360_IINLMTSEL_CHG_TYPE, 14262306a36Sopenharmony_ci MT6360_IINLMTSEL_AICR, 14362306a36Sopenharmony_ci MT6360_IINLMTSEL_LOWER_LEVEL, 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cienum mt6360_pmu_chg_type { 14762306a36Sopenharmony_ci MT6360_CHG_TYPE_NOVBUS = 0, 14862306a36Sopenharmony_ci MT6360_CHG_TYPE_UNDER_GOING, 14962306a36Sopenharmony_ci MT6360_CHG_TYPE_SDP, 15062306a36Sopenharmony_ci MT6360_CHG_TYPE_SDPNSTD, 15162306a36Sopenharmony_ci MT6360_CHG_TYPE_DCP, 15262306a36Sopenharmony_ci MT6360_CHG_TYPE_CDP, 15362306a36Sopenharmony_ci MT6360_CHG_TYPE_DISABLE_BC12, 15462306a36Sopenharmony_ci MT6360_CHG_TYPE_MAX, 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic enum power_supply_usb_type mt6360_charger_usb_types[] = { 15862306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_UNKNOWN, 15962306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_SDP, 16062306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_DCP, 16162306a36Sopenharmony_ci POWER_SUPPLY_USB_TYPE_CDP, 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int mt6360_get_chrdet_ext_stat(struct mt6360_chg_info *mci, 16562306a36Sopenharmony_ci bool *pwr_rdy) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci int ret; 16862306a36Sopenharmony_ci unsigned int regval; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_FOD_STAT, ®val); 17162306a36Sopenharmony_ci if (ret < 0) 17262306a36Sopenharmony_ci return ret; 17362306a36Sopenharmony_ci *pwr_rdy = (regval & MT6360_CHRDET_EXT_MASK) ? true : false; 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int mt6360_charger_get_online(struct mt6360_chg_info *mci, 17862306a36Sopenharmony_ci union power_supply_propval *val) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci int ret; 18162306a36Sopenharmony_ci bool pwr_rdy; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy); 18462306a36Sopenharmony_ci if (ret < 0) 18562306a36Sopenharmony_ci return ret; 18662306a36Sopenharmony_ci val->intval = pwr_rdy ? true : false; 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int mt6360_charger_get_status(struct mt6360_chg_info *mci, 19162306a36Sopenharmony_ci union power_supply_propval *val) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci int status, ret; 19462306a36Sopenharmony_ci unsigned int regval; 19562306a36Sopenharmony_ci bool pwr_rdy; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy); 19862306a36Sopenharmony_ci if (ret < 0) 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci if (!pwr_rdy) { 20162306a36Sopenharmony_ci status = POWER_SUPPLY_STATUS_DISCHARGING; 20262306a36Sopenharmony_ci goto out; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, ®val); 20662306a36Sopenharmony_ci if (ret < 0) 20762306a36Sopenharmony_ci return ret; 20862306a36Sopenharmony_ci regval &= MT6360_CHG_STAT_MASK; 20962306a36Sopenharmony_ci regval >>= MT6360_CHG_STAT_SHFT; 21062306a36Sopenharmony_ci switch (regval) { 21162306a36Sopenharmony_ci case 0x0: 21262306a36Sopenharmony_ci status = POWER_SUPPLY_STATUS_NOT_CHARGING; 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci case 0x1: 21562306a36Sopenharmony_ci status = POWER_SUPPLY_STATUS_CHARGING; 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci case 0x2: 21862306a36Sopenharmony_ci status = POWER_SUPPLY_STATUS_FULL; 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci default: 22162306a36Sopenharmony_ci ret = -EIO; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ciout: 22462306a36Sopenharmony_ci if (!ret) 22562306a36Sopenharmony_ci val->intval = status; 22662306a36Sopenharmony_ci return ret; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int mt6360_charger_get_charge_type(struct mt6360_chg_info *mci, 23062306a36Sopenharmony_ci union power_supply_propval *val) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int type, ret; 23362306a36Sopenharmony_ci unsigned int regval; 23462306a36Sopenharmony_ci u8 chg_stat; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, ®val); 23762306a36Sopenharmony_ci if (ret < 0) 23862306a36Sopenharmony_ci return ret; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci chg_stat = (regval & MT6360_CHG_STAT_MASK) >> MT6360_CHG_STAT_SHFT; 24162306a36Sopenharmony_ci switch (chg_stat) { 24262306a36Sopenharmony_ci case 0x01: /* Charge in Progress */ 24362306a36Sopenharmony_ci if (regval & MT6360_VBAT_LVL_MASK) 24462306a36Sopenharmony_ci type = POWER_SUPPLY_CHARGE_TYPE_FAST; 24562306a36Sopenharmony_ci else 24662306a36Sopenharmony_ci type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case 0x00: /* Not Charging */ 24962306a36Sopenharmony_ci case 0x02: /* Charge Done */ 25062306a36Sopenharmony_ci case 0x03: /* Charge Fault */ 25162306a36Sopenharmony_ci default: 25262306a36Sopenharmony_ci type = POWER_SUPPLY_CHARGE_TYPE_NONE; 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci val->intval = type; 25762306a36Sopenharmony_ci return 0; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int mt6360_charger_get_ichg(struct mt6360_chg_info *mci, 26162306a36Sopenharmony_ci union power_supply_propval *val) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci int ret; 26462306a36Sopenharmony_ci u32 sel, value; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL7, &sel); 26762306a36Sopenharmony_ci if (ret < 0) 26862306a36Sopenharmony_ci return ret; 26962306a36Sopenharmony_ci sel = (sel & MT6360_ICHG_MASK) >> MT6360_ICHG_SHFT; 27062306a36Sopenharmony_ci ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_ICHG], sel, &value); 27162306a36Sopenharmony_ci if (!ret) 27262306a36Sopenharmony_ci val->intval = value; 27362306a36Sopenharmony_ci return ret; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int mt6360_charger_get_max_ichg(struct mt6360_chg_info *mci, 27762306a36Sopenharmony_ci union power_supply_propval *val) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci val->intval = MT6360_ICHG_MAX; 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int mt6360_charger_get_cv(struct mt6360_chg_info *mci, 28462306a36Sopenharmony_ci union power_supply_propval *val) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int ret; 28762306a36Sopenharmony_ci u32 sel, value; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL4, &sel); 29062306a36Sopenharmony_ci if (ret < 0) 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci sel = (sel & MT6360_VOREG_MASK) >> MT6360_VOREG_SHFT; 29362306a36Sopenharmony_ci ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VOREG], sel, &value); 29462306a36Sopenharmony_ci if (!ret) 29562306a36Sopenharmony_ci val->intval = value; 29662306a36Sopenharmony_ci return ret; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int mt6360_charger_get_max_cv(struct mt6360_chg_info *mci, 30062306a36Sopenharmony_ci union power_supply_propval *val) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci val->intval = MT6360_VOREG_MAX; 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int mt6360_charger_get_aicr(struct mt6360_chg_info *mci, 30762306a36Sopenharmony_ci union power_supply_propval *val) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci int ret; 31062306a36Sopenharmony_ci u32 sel, value; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL3, &sel); 31362306a36Sopenharmony_ci if (ret < 0) 31462306a36Sopenharmony_ci return ret; 31562306a36Sopenharmony_ci sel = (sel & MT6360_IAICR_MASK) >> MT6360_IAICR_SHFT; 31662306a36Sopenharmony_ci ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_AICR], sel, &value); 31762306a36Sopenharmony_ci if (!ret) 31862306a36Sopenharmony_ci val->intval = value; 31962306a36Sopenharmony_ci return ret; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int mt6360_charger_get_mivr(struct mt6360_chg_info *mci, 32362306a36Sopenharmony_ci union power_supply_propval *val) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci int ret; 32662306a36Sopenharmony_ci u32 sel, value; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL6, &sel); 32962306a36Sopenharmony_ci if (ret < 0) 33062306a36Sopenharmony_ci return ret; 33162306a36Sopenharmony_ci sel = (sel & MT6360_VMIVR_MASK) >> MT6360_VMIVR_SHFT; 33262306a36Sopenharmony_ci ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VMIVR], sel, &value); 33362306a36Sopenharmony_ci if (!ret) 33462306a36Sopenharmony_ci val->intval = value; 33562306a36Sopenharmony_ci return ret; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int mt6360_charger_get_iprechg(struct mt6360_chg_info *mci, 33962306a36Sopenharmony_ci union power_supply_propval *val) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci int ret; 34262306a36Sopenharmony_ci u32 sel, value; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL8, &sel); 34562306a36Sopenharmony_ci if (ret < 0) 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci sel = (sel & MT6360_IPREC_MASK) >> MT6360_IPREC_SHFT; 34862306a36Sopenharmony_ci ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IPREC], sel, &value); 34962306a36Sopenharmony_ci if (!ret) 35062306a36Sopenharmony_ci val->intval = value; 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int mt6360_charger_get_ieoc(struct mt6360_chg_info *mci, 35562306a36Sopenharmony_ci union power_supply_propval *val) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci u32 sel, value; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL9, &sel); 36162306a36Sopenharmony_ci if (ret < 0) 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci sel = (sel & MT6360_IEOC_MASK) >> MT6360_IEOC_SHFT; 36462306a36Sopenharmony_ci ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IEOC], sel, &value); 36562306a36Sopenharmony_ci if (!ret) 36662306a36Sopenharmony_ci val->intval = value; 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int mt6360_charger_set_online(struct mt6360_chg_info *mci, 37162306a36Sopenharmony_ci const union power_supply_propval *val) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci u8 force_sleep = val->intval ? 0 : 1; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return regmap_update_bits(mci->regmap, 37662306a36Sopenharmony_ci MT6360_PMU_CHG_CTRL1, 37762306a36Sopenharmony_ci MT6360_FSLP_MASK, 37862306a36Sopenharmony_ci force_sleep << MT6360_FSLP_SHFT); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int mt6360_charger_set_ichg(struct mt6360_chg_info *mci, 38262306a36Sopenharmony_ci const union power_supply_propval *val) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci u32 sel; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_ICHG], val->intval, &sel); 38762306a36Sopenharmony_ci return regmap_update_bits(mci->regmap, 38862306a36Sopenharmony_ci MT6360_PMU_CHG_CTRL7, 38962306a36Sopenharmony_ci MT6360_ICHG_MASK, 39062306a36Sopenharmony_ci sel << MT6360_ICHG_SHFT); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int mt6360_charger_set_cv(struct mt6360_chg_info *mci, 39462306a36Sopenharmony_ci const union power_supply_propval *val) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci u32 sel; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VOREG], val->intval, &sel); 39962306a36Sopenharmony_ci return regmap_update_bits(mci->regmap, 40062306a36Sopenharmony_ci MT6360_PMU_CHG_CTRL4, 40162306a36Sopenharmony_ci MT6360_VOREG_MASK, 40262306a36Sopenharmony_ci sel << MT6360_VOREG_SHFT); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int mt6360_charger_set_aicr(struct mt6360_chg_info *mci, 40662306a36Sopenharmony_ci const union power_supply_propval *val) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci u32 sel; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_AICR], val->intval, &sel); 41162306a36Sopenharmony_ci return regmap_update_bits(mci->regmap, 41262306a36Sopenharmony_ci MT6360_PMU_CHG_CTRL3, 41362306a36Sopenharmony_ci MT6360_IAICR_MASK, 41462306a36Sopenharmony_ci sel << MT6360_IAICR_SHFT); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic int mt6360_charger_set_mivr(struct mt6360_chg_info *mci, 41862306a36Sopenharmony_ci const union power_supply_propval *val) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci u32 sel; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VMIVR], val->intval, &sel); 42362306a36Sopenharmony_ci return regmap_update_bits(mci->regmap, 42462306a36Sopenharmony_ci MT6360_PMU_CHG_CTRL3, 42562306a36Sopenharmony_ci MT6360_VMIVR_MASK, 42662306a36Sopenharmony_ci sel << MT6360_VMIVR_SHFT); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int mt6360_charger_set_iprechg(struct mt6360_chg_info *mci, 43062306a36Sopenharmony_ci const union power_supply_propval *val) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci u32 sel; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IPREC], val->intval, &sel); 43562306a36Sopenharmony_ci return regmap_update_bits(mci->regmap, 43662306a36Sopenharmony_ci MT6360_PMU_CHG_CTRL8, 43762306a36Sopenharmony_ci MT6360_IPREC_MASK, 43862306a36Sopenharmony_ci sel << MT6360_IPREC_SHFT); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int mt6360_charger_set_ieoc(struct mt6360_chg_info *mci, 44262306a36Sopenharmony_ci const union power_supply_propval *val) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci u32 sel; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IEOC], val->intval, &sel); 44762306a36Sopenharmony_ci return regmap_update_bits(mci->regmap, 44862306a36Sopenharmony_ci MT6360_PMU_CHG_CTRL9, 44962306a36Sopenharmony_ci MT6360_IEOC_MASK, 45062306a36Sopenharmony_ci sel << MT6360_IEOC_SHFT); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int mt6360_charger_get_property(struct power_supply *psy, 45462306a36Sopenharmony_ci enum power_supply_property psp, 45562306a36Sopenharmony_ci union power_supply_propval *val) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct mt6360_chg_info *mci = power_supply_get_drvdata(psy); 45862306a36Sopenharmony_ci int ret = 0; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci switch (psp) { 46162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 46262306a36Sopenharmony_ci ret = mt6360_charger_get_online(mci, val); 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 46562306a36Sopenharmony_ci ret = mt6360_charger_get_status(mci, val); 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TYPE: 46862306a36Sopenharmony_ci ret = mt6360_charger_get_charge_type(mci, val); 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 47162306a36Sopenharmony_ci ret = mt6360_charger_get_ichg(mci, val); 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 47462306a36Sopenharmony_ci ret = mt6360_charger_get_max_ichg(mci, val); 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 47762306a36Sopenharmony_ci ret = mt6360_charger_get_cv(mci, val); 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 48062306a36Sopenharmony_ci ret = mt6360_charger_get_max_cv(mci, val); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 48362306a36Sopenharmony_ci ret = mt6360_charger_get_aicr(mci, val); 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: 48662306a36Sopenharmony_ci ret = mt6360_charger_get_mivr(mci, val); 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 48962306a36Sopenharmony_ci ret = mt6360_charger_get_iprechg(mci, val); 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 49262306a36Sopenharmony_ci ret = mt6360_charger_get_ieoc(mci, val); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_USB_TYPE: 49562306a36Sopenharmony_ci val->intval = mci->psy_usb_type; 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci default: 49862306a36Sopenharmony_ci ret = -ENODATA; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci return ret; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic int mt6360_charger_set_property(struct power_supply *psy, 50462306a36Sopenharmony_ci enum power_supply_property psp, 50562306a36Sopenharmony_ci const union power_supply_propval *val) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct mt6360_chg_info *mci = power_supply_get_drvdata(psy); 50862306a36Sopenharmony_ci int ret; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci switch (psp) { 51162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 51262306a36Sopenharmony_ci ret = mt6360_charger_set_online(mci, val); 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 51562306a36Sopenharmony_ci ret = mt6360_charger_set_ichg(mci, val); 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 51862306a36Sopenharmony_ci ret = mt6360_charger_set_cv(mci, val); 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 52162306a36Sopenharmony_ci ret = mt6360_charger_set_aicr(mci, val); 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: 52462306a36Sopenharmony_ci ret = mt6360_charger_set_mivr(mci, val); 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 52762306a36Sopenharmony_ci ret = mt6360_charger_set_iprechg(mci, val); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 53062306a36Sopenharmony_ci ret = mt6360_charger_set_ieoc(mci, val); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci default: 53362306a36Sopenharmony_ci ret = -EINVAL; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci return ret; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int mt6360_charger_property_is_writeable(struct power_supply *psy, 53962306a36Sopenharmony_ci enum power_supply_property psp) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci switch (psp) { 54262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 54362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 54462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 54562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 54662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: 54762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: 54862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 54962306a36Sopenharmony_ci return 1; 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic enum power_supply_property mt6360_charger_properties[] = { 55662306a36Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 55762306a36Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 55862306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TYPE, 55962306a36Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 56062306a36Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 56162306a36Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 56262306a36Sopenharmony_ci POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 56362306a36Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 56462306a36Sopenharmony_ci POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, 56562306a36Sopenharmony_ci POWER_SUPPLY_PROP_PRECHARGE_CURRENT, 56662306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 56762306a36Sopenharmony_ci POWER_SUPPLY_PROP_USB_TYPE, 56862306a36Sopenharmony_ci}; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic const struct power_supply_desc mt6360_charger_desc = { 57162306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 57262306a36Sopenharmony_ci .properties = mt6360_charger_properties, 57362306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(mt6360_charger_properties), 57462306a36Sopenharmony_ci .get_property = mt6360_charger_get_property, 57562306a36Sopenharmony_ci .set_property = mt6360_charger_set_property, 57662306a36Sopenharmony_ci .property_is_writeable = mt6360_charger_property_is_writeable, 57762306a36Sopenharmony_ci .usb_types = mt6360_charger_usb_types, 57862306a36Sopenharmony_ci .num_usb_types = ARRAY_SIZE(mt6360_charger_usb_types), 57962306a36Sopenharmony_ci}; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic const struct regulator_ops mt6360_chg_otg_ops = { 58262306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 58362306a36Sopenharmony_ci .enable = regulator_enable_regmap, 58462306a36Sopenharmony_ci .disable = regulator_disable_regmap, 58562306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 58662306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 58762306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 58862306a36Sopenharmony_ci}; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic const struct regulator_desc mt6360_otg_rdesc = { 59162306a36Sopenharmony_ci .of_match = "usb-otg-vbus", 59262306a36Sopenharmony_ci .name = "usb-otg-vbus", 59362306a36Sopenharmony_ci .ops = &mt6360_chg_otg_ops, 59462306a36Sopenharmony_ci .owner = THIS_MODULE, 59562306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 59662306a36Sopenharmony_ci .min_uV = 4425000, 59762306a36Sopenharmony_ci .uV_step = 25000, 59862306a36Sopenharmony_ci .n_voltages = 57, 59962306a36Sopenharmony_ci .vsel_reg = MT6360_PMU_CHG_CTRL5, 60062306a36Sopenharmony_ci .vsel_mask = MT6360_VOBST_MASK, 60162306a36Sopenharmony_ci .enable_reg = MT6360_PMU_CHG_CTRL1, 60262306a36Sopenharmony_ci .enable_mask = MT6360_OPA_MODE_MASK, 60362306a36Sopenharmony_ci}; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic irqreturn_t mt6360_pmu_attach_i_handler(int irq, void *data) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct mt6360_chg_info *mci = data; 60862306a36Sopenharmony_ci int ret; 60962306a36Sopenharmony_ci unsigned int usb_status; 61062306a36Sopenharmony_ci int last_usb_type; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci mutex_lock(&mci->chgdet_lock); 61362306a36Sopenharmony_ci if (!mci->bc12_en) { 61462306a36Sopenharmony_ci dev_warn(mci->dev, "Received attach interrupt, bc12 disabled, ignore irq\n"); 61562306a36Sopenharmony_ci goto out; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci last_usb_type = mci->psy_usb_type; 61862306a36Sopenharmony_ci /* Plug in */ 61962306a36Sopenharmony_ci ret = regmap_read(mci->regmap, MT6360_PMU_USB_STATUS1, &usb_status); 62062306a36Sopenharmony_ci if (ret < 0) 62162306a36Sopenharmony_ci goto out; 62262306a36Sopenharmony_ci usb_status &= MT6360_USB_STATUS_MASK; 62362306a36Sopenharmony_ci usb_status >>= MT6360_USB_STATUS_SHFT; 62462306a36Sopenharmony_ci switch (usb_status) { 62562306a36Sopenharmony_ci case MT6360_CHG_TYPE_NOVBUS: 62662306a36Sopenharmony_ci dev_dbg(mci->dev, "Received attach interrupt, no vbus\n"); 62762306a36Sopenharmony_ci goto out; 62862306a36Sopenharmony_ci case MT6360_CHG_TYPE_UNDER_GOING: 62962306a36Sopenharmony_ci dev_dbg(mci->dev, "Received attach interrupt, under going...\n"); 63062306a36Sopenharmony_ci goto out; 63162306a36Sopenharmony_ci case MT6360_CHG_TYPE_SDP: 63262306a36Sopenharmony_ci mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case MT6360_CHG_TYPE_SDPNSTD: 63562306a36Sopenharmony_ci mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci case MT6360_CHG_TYPE_CDP: 63862306a36Sopenharmony_ci mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci case MT6360_CHG_TYPE_DCP: 64162306a36Sopenharmony_ci mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci case MT6360_CHG_TYPE_DISABLE_BC12: 64462306a36Sopenharmony_ci dev_dbg(mci->dev, "Received attach interrupt, bc12 detect not enable\n"); 64562306a36Sopenharmony_ci goto out; 64662306a36Sopenharmony_ci default: 64762306a36Sopenharmony_ci mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 64862306a36Sopenharmony_ci dev_dbg(mci->dev, "Received attach interrupt, reserved address\n"); 64962306a36Sopenharmony_ci goto out; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci dev_dbg(mci->dev, "Received attach interrupt, chg_type = %d\n", mci->psy_usb_type); 65362306a36Sopenharmony_ci if (last_usb_type != mci->psy_usb_type) 65462306a36Sopenharmony_ci power_supply_changed(mci->psy); 65562306a36Sopenharmony_ciout: 65662306a36Sopenharmony_ci mutex_unlock(&mci->chgdet_lock); 65762306a36Sopenharmony_ci return IRQ_HANDLED; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic void mt6360_handle_chrdet_ext_evt(struct mt6360_chg_info *mci) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci int ret; 66362306a36Sopenharmony_ci bool pwr_rdy; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci mutex_lock(&mci->chgdet_lock); 66662306a36Sopenharmony_ci ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy); 66762306a36Sopenharmony_ci if (ret < 0) 66862306a36Sopenharmony_ci goto out; 66962306a36Sopenharmony_ci if (mci->pwr_rdy == pwr_rdy) { 67062306a36Sopenharmony_ci dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy is same(%d)\n", pwr_rdy); 67162306a36Sopenharmony_ci goto out; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci mci->pwr_rdy = pwr_rdy; 67462306a36Sopenharmony_ci dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy = %d\n", pwr_rdy); 67562306a36Sopenharmony_ci if (!pwr_rdy) { 67662306a36Sopenharmony_ci mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 67762306a36Sopenharmony_ci power_supply_changed(mci->psy); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci ret = regmap_update_bits(mci->regmap, 68162306a36Sopenharmony_ci MT6360_PMU_DEVICE_TYPE, 68262306a36Sopenharmony_ci MT6360_USBCHGEN_MASK, 68362306a36Sopenharmony_ci pwr_rdy ? MT6360_USBCHGEN_MASK : 0); 68462306a36Sopenharmony_ci if (ret < 0) 68562306a36Sopenharmony_ci goto out; 68662306a36Sopenharmony_ci mci->bc12_en = pwr_rdy; 68762306a36Sopenharmony_ciout: 68862306a36Sopenharmony_ci mutex_unlock(&mci->chgdet_lock); 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic void mt6360_chrdet_work(struct work_struct *work) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct mt6360_chg_info *mci = (struct mt6360_chg_info *)container_of( 69462306a36Sopenharmony_ci work, struct mt6360_chg_info, chrdet_work); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci mt6360_handle_chrdet_ext_evt(mci); 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic irqreturn_t mt6360_pmu_chrdet_ext_evt_handler(int irq, void *data) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct mt6360_chg_info *mci = data; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci mt6360_handle_chrdet_ext_evt(mci); 70462306a36Sopenharmony_ci return IRQ_HANDLED; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic int mt6360_chg_irq_register(struct platform_device *pdev) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci const struct { 71062306a36Sopenharmony_ci const char *name; 71162306a36Sopenharmony_ci irq_handler_t handler; 71262306a36Sopenharmony_ci } irq_descs[] = { 71362306a36Sopenharmony_ci { "attach_i", mt6360_pmu_attach_i_handler }, 71462306a36Sopenharmony_ci { "chrdet_ext_evt", mt6360_pmu_chrdet_ext_evt_handler } 71562306a36Sopenharmony_ci }; 71662306a36Sopenharmony_ci int i, ret; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(irq_descs); i++) { 71962306a36Sopenharmony_ci ret = platform_get_irq_byname(pdev, irq_descs[i].name); 72062306a36Sopenharmony_ci if (ret < 0) 72162306a36Sopenharmony_ci return ret; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, ret, NULL, 72462306a36Sopenharmony_ci irq_descs[i].handler, 72562306a36Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 72662306a36Sopenharmony_ci irq_descs[i].name, 72762306a36Sopenharmony_ci platform_get_drvdata(pdev)); 72862306a36Sopenharmony_ci if (ret < 0) 72962306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, "Failed to request %s irq\n", 73062306a36Sopenharmony_ci irq_descs[i].name); 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic u32 mt6360_vinovp_trans_to_sel(u32 val) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci u32 vinovp_tbl[] = { 5500000, 6500000, 11000000, 14500000 }; 73962306a36Sopenharmony_ci int i; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Select the smaller and equal supported value */ 74262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vinovp_tbl)-1; i++) { 74362306a36Sopenharmony_ci if (val < vinovp_tbl[i+1]) 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci return i; 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int mt6360_chg_init_setting(struct mt6360_chg_info *mci) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci int ret; 75262306a36Sopenharmony_ci u32 sel; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci sel = mt6360_vinovp_trans_to_sel(mci->vinovp); 75562306a36Sopenharmony_ci ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL19, 75662306a36Sopenharmony_ci MT6360_VINOVP_MASK, sel << MT6360_VINOVP_SHFT); 75762306a36Sopenharmony_ci if (ret) 75862306a36Sopenharmony_ci return dev_err_probe(mci->dev, ret, "%s: Failed to apply vinovp\n", __func__); 75962306a36Sopenharmony_ci ret = regmap_update_bits(mci->regmap, MT6360_PMU_DEVICE_TYPE, 76062306a36Sopenharmony_ci MT6360_USBCHGEN_MASK, 0); 76162306a36Sopenharmony_ci if (ret) 76262306a36Sopenharmony_ci return dev_err_probe(mci->dev, ret, "%s: Failed to disable bc12\n", __func__); 76362306a36Sopenharmony_ci ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL2, 76462306a36Sopenharmony_ci MT6360_IINLMTSEL_MASK, 76562306a36Sopenharmony_ci MT6360_IINLMTSEL_AICR << 76662306a36Sopenharmony_ci MT6360_IINLMTSEL_SHFT); 76762306a36Sopenharmony_ci if (ret) 76862306a36Sopenharmony_ci return dev_err_probe(mci->dev, ret, 76962306a36Sopenharmony_ci "%s: Failed to switch iinlmtsel to aicr\n", __func__); 77062306a36Sopenharmony_ci usleep_range(5000, 6000); 77162306a36Sopenharmony_ci ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL3, 77262306a36Sopenharmony_ci MT6360_ILIM_EN_MASK, 0); 77362306a36Sopenharmony_ci if (ret) 77462306a36Sopenharmony_ci return dev_err_probe(mci->dev, ret, 77562306a36Sopenharmony_ci "%s: Failed to disable ilim\n", __func__); 77662306a36Sopenharmony_ci ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL10, 77762306a36Sopenharmony_ci MT6360_OTG_OC_MASK, MT6360_OTG_OC_MASK); 77862306a36Sopenharmony_ci if (ret) 77962306a36Sopenharmony_ci return dev_err_probe(mci->dev, ret, 78062306a36Sopenharmony_ci "%s: Failed to config otg oc to 3A\n", __func__); 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int mt6360_charger_probe(struct platform_device *pdev) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct mt6360_chg_info *mci; 78762306a36Sopenharmony_ci struct power_supply_config charger_cfg = {}; 78862306a36Sopenharmony_ci struct regulator_config config = { }; 78962306a36Sopenharmony_ci int ret; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci mci = devm_kzalloc(&pdev->dev, sizeof(*mci), GFP_KERNEL); 79262306a36Sopenharmony_ci if (!mci) 79362306a36Sopenharmony_ci return -ENOMEM; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci mci->dev = &pdev->dev; 79662306a36Sopenharmony_ci mci->vinovp = 6500000; 79762306a36Sopenharmony_ci mutex_init(&mci->chgdet_lock); 79862306a36Sopenharmony_ci platform_set_drvdata(pdev, mci); 79962306a36Sopenharmony_ci ret = devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work); 80062306a36Sopenharmony_ci if (ret) 80162306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, "Failed to set delayed work\n"); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci ret = device_property_read_u32(&pdev->dev, "richtek,vinovp-microvolt", &mci->vinovp); 80462306a36Sopenharmony_ci if (ret) 80562306a36Sopenharmony_ci dev_warn(&pdev->dev, "Failed to parse vinovp in DT, keep default 6.5v\n"); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci mci->regmap = dev_get_regmap(pdev->dev.parent, NULL); 80862306a36Sopenharmony_ci if (!mci->regmap) 80962306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, -ENODEV, "Failed to get parent regmap\n"); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci ret = mt6360_chg_init_setting(mci); 81262306a36Sopenharmony_ci if (ret) 81362306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, "Failed to initial setting\n"); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci memcpy(&mci->psy_desc, &mt6360_charger_desc, sizeof(mci->psy_desc)); 81662306a36Sopenharmony_ci mci->psy_desc.name = dev_name(&pdev->dev); 81762306a36Sopenharmony_ci charger_cfg.drv_data = mci; 81862306a36Sopenharmony_ci charger_cfg.of_node = pdev->dev.of_node; 81962306a36Sopenharmony_ci mci->psy = devm_power_supply_register(&pdev->dev, 82062306a36Sopenharmony_ci &mci->psy_desc, &charger_cfg); 82162306a36Sopenharmony_ci if (IS_ERR(mci->psy)) 82262306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(mci->psy), 82362306a36Sopenharmony_ci "Failed to register power supply dev\n"); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci ret = mt6360_chg_irq_register(pdev); 82762306a36Sopenharmony_ci if (ret) 82862306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, "Failed to register irqs\n"); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci config.dev = &pdev->dev; 83162306a36Sopenharmony_ci config.regmap = mci->regmap; 83262306a36Sopenharmony_ci mci->otg_rdev = devm_regulator_register(&pdev->dev, &mt6360_otg_rdesc, 83362306a36Sopenharmony_ci &config); 83462306a36Sopenharmony_ci if (IS_ERR(mci->otg_rdev)) 83562306a36Sopenharmony_ci return PTR_ERR(mci->otg_rdev); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci schedule_work(&mci->chrdet_work); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci return 0; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused mt6360_charger_of_id[] = { 84362306a36Sopenharmony_ci { .compatible = "mediatek,mt6360-chg", }, 84462306a36Sopenharmony_ci {}, 84562306a36Sopenharmony_ci}; 84662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mt6360_charger_of_id); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic const struct platform_device_id mt6360_charger_id[] = { 84962306a36Sopenharmony_ci { "mt6360-chg", 0 }, 85062306a36Sopenharmony_ci {}, 85162306a36Sopenharmony_ci}; 85262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, mt6360_charger_id); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic struct platform_driver mt6360_charger_driver = { 85562306a36Sopenharmony_ci .driver = { 85662306a36Sopenharmony_ci .name = "mt6360-chg", 85762306a36Sopenharmony_ci .of_match_table = of_match_ptr(mt6360_charger_of_id), 85862306a36Sopenharmony_ci }, 85962306a36Sopenharmony_ci .probe = mt6360_charger_probe, 86062306a36Sopenharmony_ci .id_table = mt6360_charger_id, 86162306a36Sopenharmony_ci}; 86262306a36Sopenharmony_cimodule_platform_driver(mt6360_charger_driver); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ciMODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>"); 86562306a36Sopenharmony_ciMODULE_DESCRIPTION("MT6360 Charger Driver"); 86662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 867