cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mt6360_charger.c (23960B)


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