1b7653853SJakob Hauser // SPDX-License-Identifier: GPL-2.0-only 2b7653853SJakob Hauser /* 3b7653853SJakob Hauser * Battery charger driver for RT5033 4b7653853SJakob Hauser * 5b7653853SJakob Hauser * Copyright (C) 2014 Samsung Electronics, Co., Ltd. 6b7653853SJakob Hauser * Author: Beomho Seo <beomho.seo@samsung.com> 7b7653853SJakob Hauser */ 8b7653853SJakob Hauser 98242336dSJakob Hauser #include <linux/devm-helpers.h> 108242336dSJakob Hauser #include <linux/extcon.h> 112ce8284cSRob Herring #include <linux/mod_devicetable.h> 12b7653853SJakob Hauser #include <linux/module.h> 138242336dSJakob Hauser #include <linux/mutex.h> 148242336dSJakob Hauser #include <linux/of.h> 15b7653853SJakob Hauser #include <linux/platform_device.h> 16b7653853SJakob Hauser #include <linux/power_supply.h> 17b7653853SJakob Hauser #include <linux/regmap.h> 18b7653853SJakob Hauser #include <linux/mfd/rt5033-private.h> 19b7653853SJakob Hauser 20b7653853SJakob Hauser struct rt5033_charger_data { 21b7653853SJakob Hauser unsigned int pre_uamp; 22b7653853SJakob Hauser unsigned int pre_uvolt; 23b7653853SJakob Hauser unsigned int const_uvolt; 24b7653853SJakob Hauser unsigned int eoc_uamp; 25b7653853SJakob Hauser unsigned int fast_uamp; 26b7653853SJakob Hauser }; 27b7653853SJakob Hauser 28b7653853SJakob Hauser struct rt5033_charger { 29b7653853SJakob Hauser struct device *dev; 30b7653853SJakob Hauser struct regmap *regmap; 31b7653853SJakob Hauser struct power_supply *psy; 321c6877f1SJakob Hauser struct rt5033_charger_data chg; 338242336dSJakob Hauser struct extcon_dev *edev; 348242336dSJakob Hauser struct notifier_block extcon_nb; 358242336dSJakob Hauser struct work_struct extcon_work; 368242336dSJakob Hauser struct mutex lock; 378242336dSJakob Hauser bool online; 388242336dSJakob Hauser bool otg; 398242336dSJakob Hauser bool mivr_enabled; 408242336dSJakob Hauser u8 cv_regval; 41b7653853SJakob Hauser }; 42b7653853SJakob Hauser 43b7653853SJakob Hauser static int rt5033_get_charger_state(struct rt5033_charger *charger) 44b7653853SJakob Hauser { 45b7653853SJakob Hauser struct regmap *regmap = charger->regmap; 46b7653853SJakob Hauser unsigned int reg_data; 47b7653853SJakob Hauser int state; 48b7653853SJakob Hauser 49b7653853SJakob Hauser if (!regmap) 50b7653853SJakob Hauser return POWER_SUPPLY_STATUS_UNKNOWN; 51b7653853SJakob Hauser 52b7653853SJakob Hauser regmap_read(regmap, RT5033_REG_CHG_STAT, ®_data); 53b7653853SJakob Hauser 54b7653853SJakob Hauser switch (reg_data & RT5033_CHG_STAT_MASK) { 55b7653853SJakob Hauser case RT5033_CHG_STAT_DISCHARGING: 56b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_DISCHARGING; 57b7653853SJakob Hauser break; 58b7653853SJakob Hauser case RT5033_CHG_STAT_CHARGING: 59b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_CHARGING; 60b7653853SJakob Hauser break; 61b7653853SJakob Hauser case RT5033_CHG_STAT_FULL: 62b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_FULL; 63b7653853SJakob Hauser break; 64b7653853SJakob Hauser case RT5033_CHG_STAT_NOT_CHARGING: 65b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_NOT_CHARGING; 66b7653853SJakob Hauser break; 67b7653853SJakob Hauser default: 68b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_UNKNOWN; 69b7653853SJakob Hauser } 70b7653853SJakob Hauser 718242336dSJakob Hauser /* For OTG mode, RT5033 would still report "charging" */ 728242336dSJakob Hauser if (charger->otg) 738242336dSJakob Hauser state = POWER_SUPPLY_STATUS_DISCHARGING; 748242336dSJakob Hauser 75b7653853SJakob Hauser return state; 76b7653853SJakob Hauser } 77b7653853SJakob Hauser 78b7653853SJakob Hauser static int rt5033_get_charger_type(struct rt5033_charger *charger) 79b7653853SJakob Hauser { 80b7653853SJakob Hauser struct regmap *regmap = charger->regmap; 81b7653853SJakob Hauser unsigned int reg_data; 82b7653853SJakob Hauser int state; 83b7653853SJakob Hauser 84b7653853SJakob Hauser regmap_read(regmap, RT5033_REG_CHG_STAT, ®_data); 85b7653853SJakob Hauser 86b7653853SJakob Hauser switch (reg_data & RT5033_CHG_STAT_TYPE_MASK) { 87b7653853SJakob Hauser case RT5033_CHG_STAT_TYPE_FAST: 88b7653853SJakob Hauser state = POWER_SUPPLY_CHARGE_TYPE_FAST; 89b7653853SJakob Hauser break; 90b7653853SJakob Hauser case RT5033_CHG_STAT_TYPE_PRE: 91b7653853SJakob Hauser state = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 92b7653853SJakob Hauser break; 93b7653853SJakob Hauser default: 94b7653853SJakob Hauser state = POWER_SUPPLY_CHARGE_TYPE_NONE; 95b7653853SJakob Hauser } 96b7653853SJakob Hauser 97b7653853SJakob Hauser return state; 98b7653853SJakob Hauser } 99b7653853SJakob Hauser 100b7653853SJakob Hauser static int rt5033_get_charger_current_limit(struct rt5033_charger *charger) 101b7653853SJakob Hauser { 102b7653853SJakob Hauser struct regmap *regmap = charger->regmap; 103b7653853SJakob Hauser unsigned int state, reg_data, data; 104b7653853SJakob Hauser 105b7653853SJakob Hauser regmap_read(regmap, RT5033_REG_CHG_CTRL5, ®_data); 106b7653853SJakob Hauser 107b7653853SJakob Hauser state = (reg_data & RT5033_CHGCTRL5_ICHG_MASK) 108b7653853SJakob Hauser >> RT5033_CHGCTRL5_ICHG_SHIFT; 109b7653853SJakob Hauser 110b7653853SJakob Hauser data = RT5033_CHARGER_FAST_CURRENT_MIN + 111b7653853SJakob Hauser RT5033_CHARGER_FAST_CURRENT_STEP_NUM * state; 112b7653853SJakob Hauser 113b7653853SJakob Hauser return data; 114b7653853SJakob Hauser } 115b7653853SJakob Hauser 116b7653853SJakob Hauser static int rt5033_get_charger_const_voltage(struct rt5033_charger *charger) 117b7653853SJakob Hauser { 118b7653853SJakob Hauser struct regmap *regmap = charger->regmap; 119b7653853SJakob Hauser unsigned int state, reg_data, data; 120b7653853SJakob Hauser 121b7653853SJakob Hauser regmap_read(regmap, RT5033_REG_CHG_CTRL2, ®_data); 122b7653853SJakob Hauser 123b7653853SJakob Hauser state = (reg_data & RT5033_CHGCTRL2_CV_MASK) 124b7653853SJakob Hauser >> RT5033_CHGCTRL2_CV_SHIFT; 125b7653853SJakob Hauser 126b7653853SJakob Hauser data = RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN + 127b7653853SJakob Hauser RT5033_CHARGER_CONST_VOLTAGE_STEP_NUM * state; 128b7653853SJakob Hauser 129b7653853SJakob Hauser return data; 130b7653853SJakob Hauser } 131b7653853SJakob Hauser 132b7653853SJakob Hauser static inline int rt5033_init_const_charge(struct rt5033_charger *charger) 133b7653853SJakob Hauser { 1341c6877f1SJakob Hauser struct rt5033_charger_data *chg = &charger->chg; 135b7653853SJakob Hauser int ret; 136b7653853SJakob Hauser unsigned int val; 137b7653853SJakob Hauser u8 reg_data; 138b7653853SJakob Hauser 139b7653853SJakob Hauser /* Set constant voltage mode */ 140b7653853SJakob Hauser if (chg->const_uvolt < RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN || 141b7653853SJakob Hauser chg->const_uvolt > RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MAX) { 142b7653853SJakob Hauser dev_err(charger->dev, 143b7653853SJakob Hauser "Value 'constant-charge-voltage-max-microvolt' out of range\n"); 144b7653853SJakob Hauser return -EINVAL; 145b7653853SJakob Hauser } 146b7653853SJakob Hauser 147b7653853SJakob Hauser if (chg->const_uvolt == RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN) 148b7653853SJakob Hauser reg_data = 0x00; 149b7653853SJakob Hauser else if (chg->const_uvolt == RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MAX) 150b7653853SJakob Hauser reg_data = RT5033_CV_MAX_VOLTAGE; 151b7653853SJakob Hauser else { 152b7653853SJakob Hauser val = chg->const_uvolt; 153b7653853SJakob Hauser val -= RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN; 154b7653853SJakob Hauser val /= RT5033_CHARGER_CONST_VOLTAGE_STEP_NUM; 155b7653853SJakob Hauser reg_data = val; 156b7653853SJakob Hauser } 157b7653853SJakob Hauser 158b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2, 159b7653853SJakob Hauser RT5033_CHGCTRL2_CV_MASK, 160b7653853SJakob Hauser reg_data << RT5033_CHGCTRL2_CV_SHIFT); 161b7653853SJakob Hauser if (ret) { 162b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 163b7653853SJakob Hauser return -EINVAL; 164b7653853SJakob Hauser } 165b7653853SJakob Hauser 1668242336dSJakob Hauser /* Store that value for later usage */ 1678242336dSJakob Hauser charger->cv_regval = reg_data; 1688242336dSJakob Hauser 169b7653853SJakob Hauser /* Set end of charge current */ 170b7653853SJakob Hauser if (chg->eoc_uamp < RT5033_CHARGER_EOC_MIN || 171b7653853SJakob Hauser chg->eoc_uamp > RT5033_CHARGER_EOC_MAX) { 172b7653853SJakob Hauser dev_err(charger->dev, 173b7653853SJakob Hauser "Value 'charge-term-current-microamp' out of range\n"); 174b7653853SJakob Hauser return -EINVAL; 175b7653853SJakob Hauser } 176b7653853SJakob Hauser 177b7653853SJakob Hauser if (chg->eoc_uamp == RT5033_CHARGER_EOC_MIN) 178b7653853SJakob Hauser reg_data = 0x01; 179b7653853SJakob Hauser else if (chg->eoc_uamp == RT5033_CHARGER_EOC_MAX) 180b7653853SJakob Hauser reg_data = 0x07; 181b7653853SJakob Hauser else { 182b7653853SJakob Hauser val = chg->eoc_uamp; 183b7653853SJakob Hauser if (val < RT5033_CHARGER_EOC_REF) { 184b7653853SJakob Hauser val -= RT5033_CHARGER_EOC_MIN; 185b7653853SJakob Hauser val /= RT5033_CHARGER_EOC_STEP_NUM1; 186b7653853SJakob Hauser reg_data = 0x01 + val; 187b7653853SJakob Hauser } else if (val > RT5033_CHARGER_EOC_REF) { 188b7653853SJakob Hauser val -= RT5033_CHARGER_EOC_REF; 189b7653853SJakob Hauser val /= RT5033_CHARGER_EOC_STEP_NUM2; 190b7653853SJakob Hauser reg_data = 0x04 + val; 191b7653853SJakob Hauser } else { 192b7653853SJakob Hauser reg_data = 0x04; 193b7653853SJakob Hauser } 194b7653853SJakob Hauser } 195b7653853SJakob Hauser 196b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, 197b7653853SJakob Hauser RT5033_CHGCTRL4_EOC_MASK, reg_data); 198b7653853SJakob Hauser if (ret) { 199b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 200b7653853SJakob Hauser return -EINVAL; 201b7653853SJakob Hauser } 202b7653853SJakob Hauser 203b7653853SJakob Hauser return 0; 204b7653853SJakob Hauser } 205b7653853SJakob Hauser 206b7653853SJakob Hauser static inline int rt5033_init_fast_charge(struct rt5033_charger *charger) 207b7653853SJakob Hauser { 2081c6877f1SJakob Hauser struct rt5033_charger_data *chg = &charger->chg; 209b7653853SJakob Hauser int ret; 210b7653853SJakob Hauser unsigned int val; 211b7653853SJakob Hauser u8 reg_data; 212b7653853SJakob Hauser 213b7653853SJakob Hauser /* Set limit input current */ 214b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, 215b7653853SJakob Hauser RT5033_CHGCTRL1_IAICR_MASK, RT5033_AICR_2000_MODE); 216b7653853SJakob Hauser if (ret) { 217b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 218b7653853SJakob Hauser return -EINVAL; 219b7653853SJakob Hauser } 220b7653853SJakob Hauser 221b7653853SJakob Hauser /* Set fast-charge mode charging current */ 222b7653853SJakob Hauser if (chg->fast_uamp < RT5033_CHARGER_FAST_CURRENT_MIN || 223b7653853SJakob Hauser chg->fast_uamp > RT5033_CHARGER_FAST_CURRENT_MAX) { 224b7653853SJakob Hauser dev_err(charger->dev, 225b7653853SJakob Hauser "Value 'constant-charge-current-max-microamp' out of range\n"); 226b7653853SJakob Hauser return -EINVAL; 227b7653853SJakob Hauser } 228b7653853SJakob Hauser 229b7653853SJakob Hauser if (chg->fast_uamp == RT5033_CHARGER_FAST_CURRENT_MIN) 230b7653853SJakob Hauser reg_data = 0x00; 231b7653853SJakob Hauser else if (chg->fast_uamp == RT5033_CHARGER_FAST_CURRENT_MAX) 232b7653853SJakob Hauser reg_data = RT5033_CHG_MAX_CURRENT; 233b7653853SJakob Hauser else { 234b7653853SJakob Hauser val = chg->fast_uamp; 235b7653853SJakob Hauser val -= RT5033_CHARGER_FAST_CURRENT_MIN; 236b7653853SJakob Hauser val /= RT5033_CHARGER_FAST_CURRENT_STEP_NUM; 237b7653853SJakob Hauser reg_data = val; 238b7653853SJakob Hauser } 239b7653853SJakob Hauser 240b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL5, 241b7653853SJakob Hauser RT5033_CHGCTRL5_ICHG_MASK, 242b7653853SJakob Hauser reg_data << RT5033_CHGCTRL5_ICHG_SHIFT); 243b7653853SJakob Hauser if (ret) { 244b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 245b7653853SJakob Hauser return -EINVAL; 246b7653853SJakob Hauser } 247b7653853SJakob Hauser 248b7653853SJakob Hauser return 0; 249b7653853SJakob Hauser } 250b7653853SJakob Hauser 251b7653853SJakob Hauser static inline int rt5033_init_pre_charge(struct rt5033_charger *charger) 252b7653853SJakob Hauser { 2531c6877f1SJakob Hauser struct rt5033_charger_data *chg = &charger->chg; 254b7653853SJakob Hauser int ret; 255b7653853SJakob Hauser unsigned int val; 256b7653853SJakob Hauser u8 reg_data; 257b7653853SJakob Hauser 258b7653853SJakob Hauser /* Set pre-charge threshold voltage */ 259b7653853SJakob Hauser if (chg->pre_uvolt < RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN || 260b7653853SJakob Hauser chg->pre_uvolt > RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MAX) { 261b7653853SJakob Hauser dev_err(charger->dev, 262b7653853SJakob Hauser "Value 'precharge-upper-limit-microvolt' out of range\n"); 263b7653853SJakob Hauser return -EINVAL; 264b7653853SJakob Hauser } 265b7653853SJakob Hauser 266b7653853SJakob Hauser if (chg->pre_uvolt == RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN) 267b7653853SJakob Hauser reg_data = 0x00; 268b7653853SJakob Hauser else if (chg->pre_uvolt == RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MAX) 269b7653853SJakob Hauser reg_data = 0x0f; 270b7653853SJakob Hauser else { 271b7653853SJakob Hauser val = chg->pre_uvolt; 272b7653853SJakob Hauser val -= RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN; 273b7653853SJakob Hauser val /= RT5033_CHARGER_PRE_THRESHOLD_STEP_NUM; 274b7653853SJakob Hauser reg_data = val; 275b7653853SJakob Hauser } 276b7653853SJakob Hauser 277b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL5, 278b7653853SJakob Hauser RT5033_CHGCTRL5_VPREC_MASK, reg_data); 279b7653853SJakob Hauser if (ret) { 280b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 281b7653853SJakob Hauser return -EINVAL; 282b7653853SJakob Hauser } 283b7653853SJakob Hauser 284b7653853SJakob Hauser /* Set pre-charge mode charging current */ 285b7653853SJakob Hauser if (chg->pre_uamp < RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN || 286b7653853SJakob Hauser chg->pre_uamp > RT5033_CHARGER_PRE_CURRENT_LIMIT_MAX) { 287b7653853SJakob Hauser dev_err(charger->dev, 288b7653853SJakob Hauser "Value 'precharge-current-microamp' out of range\n"); 289b7653853SJakob Hauser return -EINVAL; 290b7653853SJakob Hauser } 291b7653853SJakob Hauser 292b7653853SJakob Hauser if (chg->pre_uamp == RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN) 293b7653853SJakob Hauser reg_data = 0x00; 294b7653853SJakob Hauser else if (chg->pre_uamp == RT5033_CHARGER_PRE_CURRENT_LIMIT_MAX) 295b7653853SJakob Hauser reg_data = RT5033_CHG_MAX_PRE_CURRENT; 296b7653853SJakob Hauser else { 297b7653853SJakob Hauser val = chg->pre_uamp; 298b7653853SJakob Hauser val -= RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN; 299b7653853SJakob Hauser val /= RT5033_CHARGER_PRE_CURRENT_STEP_NUM; 300b7653853SJakob Hauser reg_data = val; 301b7653853SJakob Hauser } 302b7653853SJakob Hauser 303b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, 304b7653853SJakob Hauser RT5033_CHGCTRL4_IPREC_MASK, 305b7653853SJakob Hauser reg_data << RT5033_CHGCTRL4_IPREC_SHIFT); 306b7653853SJakob Hauser if (ret) { 307b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 308b7653853SJakob Hauser return -EINVAL; 309b7653853SJakob Hauser } 310b7653853SJakob Hauser 311b7653853SJakob Hauser return 0; 312b7653853SJakob Hauser } 313b7653853SJakob Hauser 314b7653853SJakob Hauser static int rt5033_charger_reg_init(struct rt5033_charger *charger) 315b7653853SJakob Hauser { 316b7653853SJakob Hauser int ret = 0; 317b7653853SJakob Hauser 318b7653853SJakob Hauser /* Enable charging termination */ 319b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, 320b7653853SJakob Hauser RT5033_CHGCTRL1_TE_EN_MASK, RT5033_TE_ENABLE); 321b7653853SJakob Hauser if (ret) { 322b7653853SJakob Hauser dev_err(charger->dev, "Failed to enable charging termination.\n"); 323b7653853SJakob Hauser return -EINVAL; 324b7653853SJakob Hauser } 325b7653853SJakob Hauser 326b7653853SJakob Hauser /* 327b7653853SJakob Hauser * Disable minimum input voltage regulation (MIVR), this improves 328b7653853SJakob Hauser * the charging performance. 329b7653853SJakob Hauser */ 330b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, 331b7653853SJakob Hauser RT5033_CHGCTRL4_MIVR_MASK, RT5033_CHARGER_MIVR_DISABLE); 332b7653853SJakob Hauser if (ret) { 333b7653853SJakob Hauser dev_err(charger->dev, "Failed to disable MIVR.\n"); 334b7653853SJakob Hauser return -EINVAL; 335b7653853SJakob Hauser } 336b7653853SJakob Hauser 337b7653853SJakob Hauser ret = rt5033_init_pre_charge(charger); 338b7653853SJakob Hauser if (ret) 339b7653853SJakob Hauser return ret; 340b7653853SJakob Hauser 341b7653853SJakob Hauser ret = rt5033_init_fast_charge(charger); 342b7653853SJakob Hauser if (ret) 343b7653853SJakob Hauser return ret; 344b7653853SJakob Hauser 345b7653853SJakob Hauser ret = rt5033_init_const_charge(charger); 346b7653853SJakob Hauser if (ret) 347b7653853SJakob Hauser return ret; 348b7653853SJakob Hauser 349b7653853SJakob Hauser return 0; 350b7653853SJakob Hauser } 351b7653853SJakob Hauser 3528242336dSJakob Hauser static int rt5033_charger_set_otg(struct rt5033_charger *charger) 3538242336dSJakob Hauser { 3548242336dSJakob Hauser int ret; 3558242336dSJakob Hauser 3568242336dSJakob Hauser mutex_lock(&charger->lock); 3578242336dSJakob Hauser 3588242336dSJakob Hauser /* Set OTG boost v_out to 5 volts */ 3598242336dSJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2, 3608242336dSJakob Hauser RT5033_CHGCTRL2_CV_MASK, 3618242336dSJakob Hauser 0x37 << RT5033_CHGCTRL2_CV_SHIFT); 3628242336dSJakob Hauser if (ret) { 3638242336dSJakob Hauser dev_err(charger->dev, "Failed set OTG boost v_out\n"); 3648242336dSJakob Hauser ret = -EINVAL; 3658242336dSJakob Hauser goto out_unlock; 3668242336dSJakob Hauser } 3678242336dSJakob Hauser 3688242336dSJakob Hauser /* Set operation mode to OTG */ 3698242336dSJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, 3708242336dSJakob Hauser RT5033_CHGCTRL1_MODE_MASK, RT5033_BOOST_MODE); 3718242336dSJakob Hauser if (ret) { 3728242336dSJakob Hauser dev_err(charger->dev, "Failed to update OTG mode.\n"); 3738242336dSJakob Hauser ret = -EINVAL; 3748242336dSJakob Hauser goto out_unlock; 3758242336dSJakob Hauser } 3768242336dSJakob Hauser 3778242336dSJakob Hauser /* In case someone switched from charging to OTG directly */ 3788242336dSJakob Hauser if (charger->online) 3798242336dSJakob Hauser charger->online = false; 3808242336dSJakob Hauser 3818242336dSJakob Hauser charger->otg = true; 3828242336dSJakob Hauser 3838242336dSJakob Hauser out_unlock: 3848242336dSJakob Hauser mutex_unlock(&charger->lock); 3858242336dSJakob Hauser 3868242336dSJakob Hauser return ret; 3878242336dSJakob Hauser } 3888242336dSJakob Hauser 3898242336dSJakob Hauser static int rt5033_charger_unset_otg(struct rt5033_charger *charger) 3908242336dSJakob Hauser { 3918242336dSJakob Hauser int ret; 3928242336dSJakob Hauser u8 data; 3938242336dSJakob Hauser 3948242336dSJakob Hauser /* Restore constant voltage for charging */ 3958242336dSJakob Hauser data = charger->cv_regval; 3968242336dSJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2, 3978242336dSJakob Hauser RT5033_CHGCTRL2_CV_MASK, 3988242336dSJakob Hauser data << RT5033_CHGCTRL2_CV_SHIFT); 3998242336dSJakob Hauser if (ret) { 4008242336dSJakob Hauser dev_err(charger->dev, "Failed to restore constant voltage\n"); 4018242336dSJakob Hauser return -EINVAL; 4028242336dSJakob Hauser } 4038242336dSJakob Hauser 4048242336dSJakob Hauser /* Set operation mode to charging */ 4058242336dSJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, 4068242336dSJakob Hauser RT5033_CHGCTRL1_MODE_MASK, RT5033_CHARGER_MODE); 4078242336dSJakob Hauser if (ret) { 4088242336dSJakob Hauser dev_err(charger->dev, "Failed to update charger mode.\n"); 4098242336dSJakob Hauser return -EINVAL; 4108242336dSJakob Hauser } 4118242336dSJakob Hauser 4128242336dSJakob Hauser charger->otg = false; 4138242336dSJakob Hauser 4148242336dSJakob Hauser return 0; 4158242336dSJakob Hauser } 4168242336dSJakob Hauser 4178242336dSJakob Hauser static int rt5033_charger_set_charging(struct rt5033_charger *charger) 4188242336dSJakob Hauser { 4198242336dSJakob Hauser int ret; 4208242336dSJakob Hauser 4218242336dSJakob Hauser mutex_lock(&charger->lock); 4228242336dSJakob Hauser 4238242336dSJakob Hauser /* In case someone switched from OTG to charging directly */ 4248242336dSJakob Hauser if (charger->otg) { 4258242336dSJakob Hauser ret = rt5033_charger_unset_otg(charger); 4268242336dSJakob Hauser if (ret) { 4278242336dSJakob Hauser mutex_unlock(&charger->lock); 4288242336dSJakob Hauser return -EINVAL; 4298242336dSJakob Hauser } 4308242336dSJakob Hauser } 4318242336dSJakob Hauser 4328242336dSJakob Hauser charger->online = true; 4338242336dSJakob Hauser 4348242336dSJakob Hauser mutex_unlock(&charger->lock); 4358242336dSJakob Hauser 4368242336dSJakob Hauser return 0; 4378242336dSJakob Hauser } 4388242336dSJakob Hauser 4398242336dSJakob Hauser static int rt5033_charger_set_mivr(struct rt5033_charger *charger) 4408242336dSJakob Hauser { 4418242336dSJakob Hauser int ret; 4428242336dSJakob Hauser 4438242336dSJakob Hauser mutex_lock(&charger->lock); 4448242336dSJakob Hauser 4458242336dSJakob Hauser /* 4468242336dSJakob Hauser * When connected via USB connector type SDP (Standard Downstream Port), 4478242336dSJakob Hauser * the minimum input voltage regulation (MIVR) should be enabled. It 4488242336dSJakob Hauser * prevents an input voltage drop due to insufficient current provided 4498242336dSJakob Hauser * by the adapter or USB input. As a downside, it may reduces the 4508242336dSJakob Hauser * charging current and thus slows the charging. 4518242336dSJakob Hauser */ 4528242336dSJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, 4538242336dSJakob Hauser RT5033_CHGCTRL4_MIVR_MASK, RT5033_CHARGER_MIVR_4600MV); 4548242336dSJakob Hauser if (ret) { 4558242336dSJakob Hauser dev_err(charger->dev, "Failed to set MIVR level.\n"); 4568242336dSJakob Hauser mutex_unlock(&charger->lock); 4578242336dSJakob Hauser return -EINVAL; 4588242336dSJakob Hauser } 4598242336dSJakob Hauser 4608242336dSJakob Hauser charger->mivr_enabled = true; 4618242336dSJakob Hauser 4628242336dSJakob Hauser mutex_unlock(&charger->lock); 4638242336dSJakob Hauser 4648242336dSJakob Hauser /* Beyond this, do the same steps like setting charging */ 4658242336dSJakob Hauser rt5033_charger_set_charging(charger); 4668242336dSJakob Hauser 4678242336dSJakob Hauser return 0; 4688242336dSJakob Hauser } 4698242336dSJakob Hauser 4708242336dSJakob Hauser static int rt5033_charger_set_disconnect(struct rt5033_charger *charger) 4718242336dSJakob Hauser { 4728242336dSJakob Hauser int ret = 0; 4738242336dSJakob Hauser 4748242336dSJakob Hauser mutex_lock(&charger->lock); 4758242336dSJakob Hauser 4768242336dSJakob Hauser /* Disable MIVR if enabled */ 4778242336dSJakob Hauser if (charger->mivr_enabled) { 4788242336dSJakob Hauser ret = regmap_update_bits(charger->regmap, 4798242336dSJakob Hauser RT5033_REG_CHG_CTRL4, 4808242336dSJakob Hauser RT5033_CHGCTRL4_MIVR_MASK, 4818242336dSJakob Hauser RT5033_CHARGER_MIVR_DISABLE); 4828242336dSJakob Hauser if (ret) { 4838242336dSJakob Hauser dev_err(charger->dev, "Failed to disable MIVR.\n"); 4848242336dSJakob Hauser ret = -EINVAL; 4858242336dSJakob Hauser goto out_unlock; 4868242336dSJakob Hauser } 4878242336dSJakob Hauser 4888242336dSJakob Hauser charger->mivr_enabled = false; 4898242336dSJakob Hauser } 4908242336dSJakob Hauser 4918242336dSJakob Hauser if (charger->otg) { 4928242336dSJakob Hauser ret = rt5033_charger_unset_otg(charger); 4938242336dSJakob Hauser if (ret) { 4948242336dSJakob Hauser ret = -EINVAL; 4958242336dSJakob Hauser goto out_unlock; 4968242336dSJakob Hauser } 4978242336dSJakob Hauser } 4988242336dSJakob Hauser 4998242336dSJakob Hauser if (charger->online) 5008242336dSJakob Hauser charger->online = false; 5018242336dSJakob Hauser 5028242336dSJakob Hauser out_unlock: 5038242336dSJakob Hauser mutex_unlock(&charger->lock); 5048242336dSJakob Hauser 5058242336dSJakob Hauser return ret; 5068242336dSJakob Hauser } 5078242336dSJakob Hauser 508b7653853SJakob Hauser static enum power_supply_property rt5033_charger_props[] = { 509b7653853SJakob Hauser POWER_SUPPLY_PROP_STATUS, 510b7653853SJakob Hauser POWER_SUPPLY_PROP_CHARGE_TYPE, 511b7653853SJakob Hauser POWER_SUPPLY_PROP_CURRENT_MAX, 512b7653853SJakob Hauser POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 513b7653853SJakob Hauser POWER_SUPPLY_PROP_MODEL_NAME, 514b7653853SJakob Hauser POWER_SUPPLY_PROP_MANUFACTURER, 515b7653853SJakob Hauser POWER_SUPPLY_PROP_ONLINE, 516b7653853SJakob Hauser }; 517b7653853SJakob Hauser 518b7653853SJakob Hauser static int rt5033_charger_get_property(struct power_supply *psy, 519b7653853SJakob Hauser enum power_supply_property psp, 520b7653853SJakob Hauser union power_supply_propval *val) 521b7653853SJakob Hauser { 522b7653853SJakob Hauser struct rt5033_charger *charger = power_supply_get_drvdata(psy); 523b7653853SJakob Hauser 524b7653853SJakob Hauser switch (psp) { 525b7653853SJakob Hauser case POWER_SUPPLY_PROP_STATUS: 526b7653853SJakob Hauser val->intval = rt5033_get_charger_state(charger); 527b7653853SJakob Hauser break; 528b7653853SJakob Hauser case POWER_SUPPLY_PROP_CHARGE_TYPE: 529b7653853SJakob Hauser val->intval = rt5033_get_charger_type(charger); 530b7653853SJakob Hauser break; 531b7653853SJakob Hauser case POWER_SUPPLY_PROP_CURRENT_MAX: 532b7653853SJakob Hauser val->intval = rt5033_get_charger_current_limit(charger); 533b7653853SJakob Hauser break; 534b7653853SJakob Hauser case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 535b7653853SJakob Hauser val->intval = rt5033_get_charger_const_voltage(charger); 536b7653853SJakob Hauser break; 537b7653853SJakob Hauser case POWER_SUPPLY_PROP_MODEL_NAME: 538b7653853SJakob Hauser val->strval = RT5033_CHARGER_MODEL; 539b7653853SJakob Hauser break; 540b7653853SJakob Hauser case POWER_SUPPLY_PROP_MANUFACTURER: 541b7653853SJakob Hauser val->strval = RT5033_MANUFACTURER; 542b7653853SJakob Hauser break; 543b7653853SJakob Hauser case POWER_SUPPLY_PROP_ONLINE: 5448242336dSJakob Hauser val->intval = charger->online; 545b7653853SJakob Hauser break; 546b7653853SJakob Hauser default: 547b7653853SJakob Hauser return -EINVAL; 548b7653853SJakob Hauser } 549b7653853SJakob Hauser 550b7653853SJakob Hauser return 0; 551b7653853SJakob Hauser } 552b7653853SJakob Hauser 5531c6877f1SJakob Hauser static int rt5033_charger_dt_init(struct rt5033_charger *charger) 554b7653853SJakob Hauser { 5551c6877f1SJakob Hauser struct rt5033_charger_data *chg = &charger->chg; 556b7653853SJakob Hauser struct power_supply_battery_info *info; 557b7653853SJakob Hauser int ret; 558b7653853SJakob Hauser 559b7653853SJakob Hauser ret = power_supply_get_battery_info(charger->psy, &info); 560b7653853SJakob Hauser if (ret) 5611c6877f1SJakob Hauser return dev_err_probe(charger->dev, -EINVAL, 5621c6877f1SJakob Hauser "missing battery info\n"); 563b7653853SJakob Hauser 564b7653853SJakob Hauser /* Assign data. Validity will be checked in the init functions. */ 565b7653853SJakob Hauser chg->pre_uamp = info->precharge_current_ua; 566b7653853SJakob Hauser chg->fast_uamp = info->constant_charge_current_max_ua; 567b7653853SJakob Hauser chg->eoc_uamp = info->charge_term_current_ua; 568b7653853SJakob Hauser chg->pre_uvolt = info->precharge_voltage_max_uv; 569b7653853SJakob Hauser chg->const_uvolt = info->constant_charge_voltage_max_uv; 570b7653853SJakob Hauser 5711c6877f1SJakob Hauser return 0; 572b7653853SJakob Hauser } 573b7653853SJakob Hauser 5748242336dSJakob Hauser static void rt5033_charger_extcon_work(struct work_struct *work) 5758242336dSJakob Hauser { 5768242336dSJakob Hauser struct rt5033_charger *charger = 5778242336dSJakob Hauser container_of(work, struct rt5033_charger, extcon_work); 5788242336dSJakob Hauser struct extcon_dev *edev = charger->edev; 5798242336dSJakob Hauser int connector, state; 5808242336dSJakob Hauser int ret; 5818242336dSJakob Hauser 5828242336dSJakob Hauser for (connector = EXTCON_USB_HOST; connector <= EXTCON_CHG_USB_PD; 5838242336dSJakob Hauser connector++) { 5848242336dSJakob Hauser state = extcon_get_state(edev, connector); 5858242336dSJakob Hauser if (state == 1) 5868242336dSJakob Hauser break; 5878242336dSJakob Hauser } 5888242336dSJakob Hauser 5898242336dSJakob Hauser /* 5908242336dSJakob Hauser * Adding a delay between extcon notification and extcon action. This 5918242336dSJakob Hauser * makes extcon action execution more reliable. Without the delay the 5928242336dSJakob Hauser * execution sometimes fails, possibly because the chip is busy or not 5938242336dSJakob Hauser * ready. 5948242336dSJakob Hauser */ 5958242336dSJakob Hauser msleep(100); 5968242336dSJakob Hauser 5978242336dSJakob Hauser switch (connector) { 5988242336dSJakob Hauser case EXTCON_CHG_USB_SDP: 5998242336dSJakob Hauser ret = rt5033_charger_set_mivr(charger); 6008242336dSJakob Hauser if (ret) { 6018242336dSJakob Hauser dev_err(charger->dev, "failed to set USB mode\n"); 6028242336dSJakob Hauser break; 6038242336dSJakob Hauser } 6048242336dSJakob Hauser dev_info(charger->dev, "USB mode. connector type: %d\n", 6058242336dSJakob Hauser connector); 6068242336dSJakob Hauser break; 6078242336dSJakob Hauser case EXTCON_CHG_USB_DCP: 6088242336dSJakob Hauser case EXTCON_CHG_USB_CDP: 6098242336dSJakob Hauser case EXTCON_CHG_USB_ACA: 6108242336dSJakob Hauser case EXTCON_CHG_USB_FAST: 6118242336dSJakob Hauser case EXTCON_CHG_USB_SLOW: 6128242336dSJakob Hauser case EXTCON_CHG_WPT: 6138242336dSJakob Hauser case EXTCON_CHG_USB_PD: 6148242336dSJakob Hauser ret = rt5033_charger_set_charging(charger); 6158242336dSJakob Hauser if (ret) { 6168242336dSJakob Hauser dev_err(charger->dev, "failed to set charging\n"); 6178242336dSJakob Hauser break; 6188242336dSJakob Hauser } 6198242336dSJakob Hauser dev_info(charger->dev, "charging. connector type: %d\n", 6208242336dSJakob Hauser connector); 6218242336dSJakob Hauser break; 6228242336dSJakob Hauser case EXTCON_USB_HOST: 6238242336dSJakob Hauser ret = rt5033_charger_set_otg(charger); 6248242336dSJakob Hauser if (ret) { 6258242336dSJakob Hauser dev_err(charger->dev, "failed to set OTG\n"); 6268242336dSJakob Hauser break; 6278242336dSJakob Hauser } 6288242336dSJakob Hauser dev_info(charger->dev, "OTG enabled\n"); 6298242336dSJakob Hauser break; 6308242336dSJakob Hauser default: 6318242336dSJakob Hauser ret = rt5033_charger_set_disconnect(charger); 6328242336dSJakob Hauser if (ret) { 6338242336dSJakob Hauser dev_err(charger->dev, "failed to set disconnect\n"); 6348242336dSJakob Hauser break; 6358242336dSJakob Hauser } 6368242336dSJakob Hauser dev_info(charger->dev, "disconnected\n"); 6378242336dSJakob Hauser break; 6388242336dSJakob Hauser } 6398242336dSJakob Hauser 6408242336dSJakob Hauser power_supply_changed(charger->psy); 6418242336dSJakob Hauser } 6428242336dSJakob Hauser 6438242336dSJakob Hauser static int rt5033_charger_extcon_notifier(struct notifier_block *nb, 6448242336dSJakob Hauser unsigned long event, void *param) 6458242336dSJakob Hauser { 6468242336dSJakob Hauser struct rt5033_charger *charger = 6478242336dSJakob Hauser container_of(nb, struct rt5033_charger, extcon_nb); 6488242336dSJakob Hauser 6498242336dSJakob Hauser schedule_work(&charger->extcon_work); 6508242336dSJakob Hauser 6518242336dSJakob Hauser return NOTIFY_OK; 6528242336dSJakob Hauser } 6538242336dSJakob Hauser 654b7653853SJakob Hauser static const struct power_supply_desc rt5033_charger_desc = { 655b7653853SJakob Hauser .name = "rt5033-charger", 656b7653853SJakob Hauser .type = POWER_SUPPLY_TYPE_USB, 657b7653853SJakob Hauser .properties = rt5033_charger_props, 658b7653853SJakob Hauser .num_properties = ARRAY_SIZE(rt5033_charger_props), 659b7653853SJakob Hauser .get_property = rt5033_charger_get_property, 660b7653853SJakob Hauser }; 661b7653853SJakob Hauser 662b7653853SJakob Hauser static int rt5033_charger_probe(struct platform_device *pdev) 663b7653853SJakob Hauser { 664b7653853SJakob Hauser struct rt5033_charger *charger; 665b7653853SJakob Hauser struct power_supply_config psy_cfg = {}; 6668242336dSJakob Hauser struct device_node *np_conn, *np_edev; 667b7653853SJakob Hauser int ret; 668b7653853SJakob Hauser 669b7653853SJakob Hauser charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); 670b7653853SJakob Hauser if (!charger) 671b7653853SJakob Hauser return -ENOMEM; 672b7653853SJakob Hauser 673b7653853SJakob Hauser platform_set_drvdata(pdev, charger); 674b7653853SJakob Hauser charger->dev = &pdev->dev; 675b7653853SJakob Hauser charger->regmap = dev_get_regmap(pdev->dev.parent, NULL); 6768242336dSJakob Hauser mutex_init(&charger->lock); 677b7653853SJakob Hauser 678b7653853SJakob Hauser psy_cfg.of_node = pdev->dev.of_node; 679b7653853SJakob Hauser psy_cfg.drv_data = charger; 680b7653853SJakob Hauser 681*3f26d8b6SJakob Hauser charger->psy = devm_power_supply_register(charger->dev, 682b7653853SJakob Hauser &rt5033_charger_desc, 683b7653853SJakob Hauser &psy_cfg); 684b7653853SJakob Hauser if (IS_ERR(charger->psy)) 685*3f26d8b6SJakob Hauser return dev_err_probe(charger->dev, PTR_ERR(charger->psy), 686b7653853SJakob Hauser "Failed to register power supply\n"); 687b7653853SJakob Hauser 6881c6877f1SJakob Hauser ret = rt5033_charger_dt_init(charger); 6891c6877f1SJakob Hauser if (ret) 6901c6877f1SJakob Hauser return ret; 691b7653853SJakob Hauser 692b7653853SJakob Hauser ret = rt5033_charger_reg_init(charger); 693b7653853SJakob Hauser if (ret) 694b7653853SJakob Hauser return ret; 695b7653853SJakob Hauser 6968242336dSJakob Hauser /* 6978242336dSJakob Hauser * Extcon support is not vital for the charger to work. If no extcon 6988242336dSJakob Hauser * is available, just emit a warning and leave the probe function. 6998242336dSJakob Hauser */ 7008242336dSJakob Hauser np_conn = of_parse_phandle(pdev->dev.of_node, "richtek,usb-connector", 0); 7018242336dSJakob Hauser np_edev = of_get_parent(np_conn); 7028242336dSJakob Hauser charger->edev = extcon_find_edev_by_node(np_edev); 7038242336dSJakob Hauser if (IS_ERR(charger->edev)) { 704*3f26d8b6SJakob Hauser dev_warn(charger->dev, "no extcon device found in device-tree\n"); 7058242336dSJakob Hauser goto out; 7068242336dSJakob Hauser } 7078242336dSJakob Hauser 708*3f26d8b6SJakob Hauser ret = devm_work_autocancel(charger->dev, &charger->extcon_work, 7098242336dSJakob Hauser rt5033_charger_extcon_work); 7108242336dSJakob Hauser if (ret) { 711*3f26d8b6SJakob Hauser dev_err(charger->dev, "failed to initialize extcon work\n"); 7128242336dSJakob Hauser return ret; 7138242336dSJakob Hauser } 7148242336dSJakob Hauser 7158242336dSJakob Hauser charger->extcon_nb.notifier_call = rt5033_charger_extcon_notifier; 716*3f26d8b6SJakob Hauser ret = devm_extcon_register_notifier_all(charger->dev, charger->edev, 7178242336dSJakob Hauser &charger->extcon_nb); 7188242336dSJakob Hauser if (ret) { 719*3f26d8b6SJakob Hauser dev_err(charger->dev, "failed to register extcon notifier\n"); 7208242336dSJakob Hauser return ret; 7218242336dSJakob Hauser } 7228242336dSJakob Hauser out: 723b7653853SJakob Hauser return 0; 724b7653853SJakob Hauser } 725b7653853SJakob Hauser 726b7653853SJakob Hauser static const struct platform_device_id rt5033_charger_id[] = { 727b7653853SJakob Hauser { "rt5033-charger", }, 728b7653853SJakob Hauser { } 729b7653853SJakob Hauser }; 730b7653853SJakob Hauser MODULE_DEVICE_TABLE(platform, rt5033_charger_id); 731b7653853SJakob Hauser 732b7653853SJakob Hauser static const struct of_device_id rt5033_charger_of_match[] = { 733b7653853SJakob Hauser { .compatible = "richtek,rt5033-charger", }, 734b7653853SJakob Hauser { } 735b7653853SJakob Hauser }; 736b7653853SJakob Hauser MODULE_DEVICE_TABLE(of, rt5033_charger_of_match); 737b7653853SJakob Hauser 738b7653853SJakob Hauser static struct platform_driver rt5033_charger_driver = { 739b7653853SJakob Hauser .driver = { 740b7653853SJakob Hauser .name = "rt5033-charger", 741b7653853SJakob Hauser .of_match_table = rt5033_charger_of_match, 742b7653853SJakob Hauser }, 743b7653853SJakob Hauser .probe = rt5033_charger_probe, 744b7653853SJakob Hauser .id_table = rt5033_charger_id, 745b7653853SJakob Hauser }; 746b7653853SJakob Hauser module_platform_driver(rt5033_charger_driver); 747b7653853SJakob Hauser 748b7653853SJakob Hauser MODULE_DESCRIPTION("Richtek RT5033 charger driver"); 749b7653853SJakob Hauser MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); 750b7653853SJakob Hauser MODULE_LICENSE("GPL v2"); 751