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 9*2ce8284cSRob Herring #include <linux/mod_devicetable.h> 10b7653853SJakob Hauser #include <linux/module.h> 11b7653853SJakob Hauser #include <linux/platform_device.h> 12b7653853SJakob Hauser #include <linux/power_supply.h> 13b7653853SJakob Hauser #include <linux/regmap.h> 14b7653853SJakob Hauser #include <linux/mfd/rt5033-private.h> 15b7653853SJakob Hauser 16b7653853SJakob Hauser struct rt5033_charger_data { 17b7653853SJakob Hauser unsigned int pre_uamp; 18b7653853SJakob Hauser unsigned int pre_uvolt; 19b7653853SJakob Hauser unsigned int const_uvolt; 20b7653853SJakob Hauser unsigned int eoc_uamp; 21b7653853SJakob Hauser unsigned int fast_uamp; 22b7653853SJakob Hauser }; 23b7653853SJakob Hauser 24b7653853SJakob Hauser struct rt5033_charger { 25b7653853SJakob Hauser struct device *dev; 26b7653853SJakob Hauser struct regmap *regmap; 27b7653853SJakob Hauser struct power_supply *psy; 28b7653853SJakob Hauser struct rt5033_charger_data *chg; 29b7653853SJakob Hauser }; 30b7653853SJakob Hauser 31b7653853SJakob Hauser static int rt5033_get_charger_state(struct rt5033_charger *charger) 32b7653853SJakob Hauser { 33b7653853SJakob Hauser struct regmap *regmap = charger->regmap; 34b7653853SJakob Hauser unsigned int reg_data; 35b7653853SJakob Hauser int state; 36b7653853SJakob Hauser 37b7653853SJakob Hauser if (!regmap) 38b7653853SJakob Hauser return POWER_SUPPLY_STATUS_UNKNOWN; 39b7653853SJakob Hauser 40b7653853SJakob Hauser regmap_read(regmap, RT5033_REG_CHG_STAT, ®_data); 41b7653853SJakob Hauser 42b7653853SJakob Hauser switch (reg_data & RT5033_CHG_STAT_MASK) { 43b7653853SJakob Hauser case RT5033_CHG_STAT_DISCHARGING: 44b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_DISCHARGING; 45b7653853SJakob Hauser break; 46b7653853SJakob Hauser case RT5033_CHG_STAT_CHARGING: 47b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_CHARGING; 48b7653853SJakob Hauser break; 49b7653853SJakob Hauser case RT5033_CHG_STAT_FULL: 50b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_FULL; 51b7653853SJakob Hauser break; 52b7653853SJakob Hauser case RT5033_CHG_STAT_NOT_CHARGING: 53b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_NOT_CHARGING; 54b7653853SJakob Hauser break; 55b7653853SJakob Hauser default: 56b7653853SJakob Hauser state = POWER_SUPPLY_STATUS_UNKNOWN; 57b7653853SJakob Hauser } 58b7653853SJakob Hauser 59b7653853SJakob Hauser return state; 60b7653853SJakob Hauser } 61b7653853SJakob Hauser 62b7653853SJakob Hauser static int rt5033_get_charger_type(struct rt5033_charger *charger) 63b7653853SJakob Hauser { 64b7653853SJakob Hauser struct regmap *regmap = charger->regmap; 65b7653853SJakob Hauser unsigned int reg_data; 66b7653853SJakob Hauser int state; 67b7653853SJakob Hauser 68b7653853SJakob Hauser regmap_read(regmap, RT5033_REG_CHG_STAT, ®_data); 69b7653853SJakob Hauser 70b7653853SJakob Hauser switch (reg_data & RT5033_CHG_STAT_TYPE_MASK) { 71b7653853SJakob Hauser case RT5033_CHG_STAT_TYPE_FAST: 72b7653853SJakob Hauser state = POWER_SUPPLY_CHARGE_TYPE_FAST; 73b7653853SJakob Hauser break; 74b7653853SJakob Hauser case RT5033_CHG_STAT_TYPE_PRE: 75b7653853SJakob Hauser state = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 76b7653853SJakob Hauser break; 77b7653853SJakob Hauser default: 78b7653853SJakob Hauser state = POWER_SUPPLY_CHARGE_TYPE_NONE; 79b7653853SJakob Hauser } 80b7653853SJakob Hauser 81b7653853SJakob Hauser return state; 82b7653853SJakob Hauser } 83b7653853SJakob Hauser 84b7653853SJakob Hauser static int rt5033_get_charger_current_limit(struct rt5033_charger *charger) 85b7653853SJakob Hauser { 86b7653853SJakob Hauser struct regmap *regmap = charger->regmap; 87b7653853SJakob Hauser unsigned int state, reg_data, data; 88b7653853SJakob Hauser 89b7653853SJakob Hauser regmap_read(regmap, RT5033_REG_CHG_CTRL5, ®_data); 90b7653853SJakob Hauser 91b7653853SJakob Hauser state = (reg_data & RT5033_CHGCTRL5_ICHG_MASK) 92b7653853SJakob Hauser >> RT5033_CHGCTRL5_ICHG_SHIFT; 93b7653853SJakob Hauser 94b7653853SJakob Hauser data = RT5033_CHARGER_FAST_CURRENT_MIN + 95b7653853SJakob Hauser RT5033_CHARGER_FAST_CURRENT_STEP_NUM * state; 96b7653853SJakob Hauser 97b7653853SJakob Hauser return data; 98b7653853SJakob Hauser } 99b7653853SJakob Hauser 100b7653853SJakob Hauser static int rt5033_get_charger_const_voltage(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_CTRL2, ®_data); 106b7653853SJakob Hauser 107b7653853SJakob Hauser state = (reg_data & RT5033_CHGCTRL2_CV_MASK) 108b7653853SJakob Hauser >> RT5033_CHGCTRL2_CV_SHIFT; 109b7653853SJakob Hauser 110b7653853SJakob Hauser data = RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN + 111b7653853SJakob Hauser RT5033_CHARGER_CONST_VOLTAGE_STEP_NUM * state; 112b7653853SJakob Hauser 113b7653853SJakob Hauser return data; 114b7653853SJakob Hauser } 115b7653853SJakob Hauser 116b7653853SJakob Hauser static inline int rt5033_init_const_charge(struct rt5033_charger *charger) 117b7653853SJakob Hauser { 118b7653853SJakob Hauser struct rt5033_charger_data *chg = charger->chg; 119b7653853SJakob Hauser int ret; 120b7653853SJakob Hauser unsigned int val; 121b7653853SJakob Hauser u8 reg_data; 122b7653853SJakob Hauser 123b7653853SJakob Hauser /* Set constant voltage mode */ 124b7653853SJakob Hauser if (chg->const_uvolt < RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN || 125b7653853SJakob Hauser chg->const_uvolt > RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MAX) { 126b7653853SJakob Hauser dev_err(charger->dev, 127b7653853SJakob Hauser "Value 'constant-charge-voltage-max-microvolt' out of range\n"); 128b7653853SJakob Hauser return -EINVAL; 129b7653853SJakob Hauser } 130b7653853SJakob Hauser 131b7653853SJakob Hauser if (chg->const_uvolt == RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN) 132b7653853SJakob Hauser reg_data = 0x00; 133b7653853SJakob Hauser else if (chg->const_uvolt == RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MAX) 134b7653853SJakob Hauser reg_data = RT5033_CV_MAX_VOLTAGE; 135b7653853SJakob Hauser else { 136b7653853SJakob Hauser val = chg->const_uvolt; 137b7653853SJakob Hauser val -= RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN; 138b7653853SJakob Hauser val /= RT5033_CHARGER_CONST_VOLTAGE_STEP_NUM; 139b7653853SJakob Hauser reg_data = val; 140b7653853SJakob Hauser } 141b7653853SJakob Hauser 142b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2, 143b7653853SJakob Hauser RT5033_CHGCTRL2_CV_MASK, 144b7653853SJakob Hauser reg_data << RT5033_CHGCTRL2_CV_SHIFT); 145b7653853SJakob Hauser if (ret) { 146b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 147b7653853SJakob Hauser return -EINVAL; 148b7653853SJakob Hauser } 149b7653853SJakob Hauser 150b7653853SJakob Hauser /* Set end of charge current */ 151b7653853SJakob Hauser if (chg->eoc_uamp < RT5033_CHARGER_EOC_MIN || 152b7653853SJakob Hauser chg->eoc_uamp > RT5033_CHARGER_EOC_MAX) { 153b7653853SJakob Hauser dev_err(charger->dev, 154b7653853SJakob Hauser "Value 'charge-term-current-microamp' out of range\n"); 155b7653853SJakob Hauser return -EINVAL; 156b7653853SJakob Hauser } 157b7653853SJakob Hauser 158b7653853SJakob Hauser if (chg->eoc_uamp == RT5033_CHARGER_EOC_MIN) 159b7653853SJakob Hauser reg_data = 0x01; 160b7653853SJakob Hauser else if (chg->eoc_uamp == RT5033_CHARGER_EOC_MAX) 161b7653853SJakob Hauser reg_data = 0x07; 162b7653853SJakob Hauser else { 163b7653853SJakob Hauser val = chg->eoc_uamp; 164b7653853SJakob Hauser if (val < RT5033_CHARGER_EOC_REF) { 165b7653853SJakob Hauser val -= RT5033_CHARGER_EOC_MIN; 166b7653853SJakob Hauser val /= RT5033_CHARGER_EOC_STEP_NUM1; 167b7653853SJakob Hauser reg_data = 0x01 + val; 168b7653853SJakob Hauser } else if (val > RT5033_CHARGER_EOC_REF) { 169b7653853SJakob Hauser val -= RT5033_CHARGER_EOC_REF; 170b7653853SJakob Hauser val /= RT5033_CHARGER_EOC_STEP_NUM2; 171b7653853SJakob Hauser reg_data = 0x04 + val; 172b7653853SJakob Hauser } else { 173b7653853SJakob Hauser reg_data = 0x04; 174b7653853SJakob Hauser } 175b7653853SJakob Hauser } 176b7653853SJakob Hauser 177b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, 178b7653853SJakob Hauser RT5033_CHGCTRL4_EOC_MASK, reg_data); 179b7653853SJakob Hauser if (ret) { 180b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 181b7653853SJakob Hauser return -EINVAL; 182b7653853SJakob Hauser } 183b7653853SJakob Hauser 184b7653853SJakob Hauser return 0; 185b7653853SJakob Hauser } 186b7653853SJakob Hauser 187b7653853SJakob Hauser static inline int rt5033_init_fast_charge(struct rt5033_charger *charger) 188b7653853SJakob Hauser { 189b7653853SJakob Hauser struct rt5033_charger_data *chg = charger->chg; 190b7653853SJakob Hauser int ret; 191b7653853SJakob Hauser unsigned int val; 192b7653853SJakob Hauser u8 reg_data; 193b7653853SJakob Hauser 194b7653853SJakob Hauser /* Set limit input current */ 195b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, 196b7653853SJakob Hauser RT5033_CHGCTRL1_IAICR_MASK, RT5033_AICR_2000_MODE); 197b7653853SJakob Hauser if (ret) { 198b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 199b7653853SJakob Hauser return -EINVAL; 200b7653853SJakob Hauser } 201b7653853SJakob Hauser 202b7653853SJakob Hauser /* Set fast-charge mode charging current */ 203b7653853SJakob Hauser if (chg->fast_uamp < RT5033_CHARGER_FAST_CURRENT_MIN || 204b7653853SJakob Hauser chg->fast_uamp > RT5033_CHARGER_FAST_CURRENT_MAX) { 205b7653853SJakob Hauser dev_err(charger->dev, 206b7653853SJakob Hauser "Value 'constant-charge-current-max-microamp' out of range\n"); 207b7653853SJakob Hauser return -EINVAL; 208b7653853SJakob Hauser } 209b7653853SJakob Hauser 210b7653853SJakob Hauser if (chg->fast_uamp == RT5033_CHARGER_FAST_CURRENT_MIN) 211b7653853SJakob Hauser reg_data = 0x00; 212b7653853SJakob Hauser else if (chg->fast_uamp == RT5033_CHARGER_FAST_CURRENT_MAX) 213b7653853SJakob Hauser reg_data = RT5033_CHG_MAX_CURRENT; 214b7653853SJakob Hauser else { 215b7653853SJakob Hauser val = chg->fast_uamp; 216b7653853SJakob Hauser val -= RT5033_CHARGER_FAST_CURRENT_MIN; 217b7653853SJakob Hauser val /= RT5033_CHARGER_FAST_CURRENT_STEP_NUM; 218b7653853SJakob Hauser reg_data = val; 219b7653853SJakob Hauser } 220b7653853SJakob Hauser 221b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL5, 222b7653853SJakob Hauser RT5033_CHGCTRL5_ICHG_MASK, 223b7653853SJakob Hauser reg_data << RT5033_CHGCTRL5_ICHG_SHIFT); 224b7653853SJakob Hauser if (ret) { 225b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 226b7653853SJakob Hauser return -EINVAL; 227b7653853SJakob Hauser } 228b7653853SJakob Hauser 229b7653853SJakob Hauser return 0; 230b7653853SJakob Hauser } 231b7653853SJakob Hauser 232b7653853SJakob Hauser static inline int rt5033_init_pre_charge(struct rt5033_charger *charger) 233b7653853SJakob Hauser { 234b7653853SJakob Hauser struct rt5033_charger_data *chg = charger->chg; 235b7653853SJakob Hauser int ret; 236b7653853SJakob Hauser unsigned int val; 237b7653853SJakob Hauser u8 reg_data; 238b7653853SJakob Hauser 239b7653853SJakob Hauser /* Set pre-charge threshold voltage */ 240b7653853SJakob Hauser if (chg->pre_uvolt < RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN || 241b7653853SJakob Hauser chg->pre_uvolt > RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MAX) { 242b7653853SJakob Hauser dev_err(charger->dev, 243b7653853SJakob Hauser "Value 'precharge-upper-limit-microvolt' out of range\n"); 244b7653853SJakob Hauser return -EINVAL; 245b7653853SJakob Hauser } 246b7653853SJakob Hauser 247b7653853SJakob Hauser if (chg->pre_uvolt == RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN) 248b7653853SJakob Hauser reg_data = 0x00; 249b7653853SJakob Hauser else if (chg->pre_uvolt == RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MAX) 250b7653853SJakob Hauser reg_data = 0x0f; 251b7653853SJakob Hauser else { 252b7653853SJakob Hauser val = chg->pre_uvolt; 253b7653853SJakob Hauser val -= RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN; 254b7653853SJakob Hauser val /= RT5033_CHARGER_PRE_THRESHOLD_STEP_NUM; 255b7653853SJakob Hauser reg_data = val; 256b7653853SJakob Hauser } 257b7653853SJakob Hauser 258b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL5, 259b7653853SJakob Hauser RT5033_CHGCTRL5_VPREC_MASK, reg_data); 260b7653853SJakob Hauser if (ret) { 261b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 262b7653853SJakob Hauser return -EINVAL; 263b7653853SJakob Hauser } 264b7653853SJakob Hauser 265b7653853SJakob Hauser /* Set pre-charge mode charging current */ 266b7653853SJakob Hauser if (chg->pre_uamp < RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN || 267b7653853SJakob Hauser chg->pre_uamp > RT5033_CHARGER_PRE_CURRENT_LIMIT_MAX) { 268b7653853SJakob Hauser dev_err(charger->dev, 269b7653853SJakob Hauser "Value 'precharge-current-microamp' out of range\n"); 270b7653853SJakob Hauser return -EINVAL; 271b7653853SJakob Hauser } 272b7653853SJakob Hauser 273b7653853SJakob Hauser if (chg->pre_uamp == RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN) 274b7653853SJakob Hauser reg_data = 0x00; 275b7653853SJakob Hauser else if (chg->pre_uamp == RT5033_CHARGER_PRE_CURRENT_LIMIT_MAX) 276b7653853SJakob Hauser reg_data = RT5033_CHG_MAX_PRE_CURRENT; 277b7653853SJakob Hauser else { 278b7653853SJakob Hauser val = chg->pre_uamp; 279b7653853SJakob Hauser val -= RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN; 280b7653853SJakob Hauser val /= RT5033_CHARGER_PRE_CURRENT_STEP_NUM; 281b7653853SJakob Hauser reg_data = val; 282b7653853SJakob Hauser } 283b7653853SJakob Hauser 284b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, 285b7653853SJakob Hauser RT5033_CHGCTRL4_IPREC_MASK, 286b7653853SJakob Hauser reg_data << RT5033_CHGCTRL4_IPREC_SHIFT); 287b7653853SJakob Hauser if (ret) { 288b7653853SJakob Hauser dev_err(charger->dev, "Failed regmap update\n"); 289b7653853SJakob Hauser return -EINVAL; 290b7653853SJakob Hauser } 291b7653853SJakob Hauser 292b7653853SJakob Hauser return 0; 293b7653853SJakob Hauser } 294b7653853SJakob Hauser 295b7653853SJakob Hauser static int rt5033_charger_reg_init(struct rt5033_charger *charger) 296b7653853SJakob Hauser { 297b7653853SJakob Hauser int ret = 0; 298b7653853SJakob Hauser 299b7653853SJakob Hauser /* Enable charging termination */ 300b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, 301b7653853SJakob Hauser RT5033_CHGCTRL1_TE_EN_MASK, RT5033_TE_ENABLE); 302b7653853SJakob Hauser if (ret) { 303b7653853SJakob Hauser dev_err(charger->dev, "Failed to enable charging termination.\n"); 304b7653853SJakob Hauser return -EINVAL; 305b7653853SJakob Hauser } 306b7653853SJakob Hauser 307b7653853SJakob Hauser /* 308b7653853SJakob Hauser * Disable minimum input voltage regulation (MIVR), this improves 309b7653853SJakob Hauser * the charging performance. 310b7653853SJakob Hauser */ 311b7653853SJakob Hauser ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, 312b7653853SJakob Hauser RT5033_CHGCTRL4_MIVR_MASK, RT5033_CHARGER_MIVR_DISABLE); 313b7653853SJakob Hauser if (ret) { 314b7653853SJakob Hauser dev_err(charger->dev, "Failed to disable MIVR.\n"); 315b7653853SJakob Hauser return -EINVAL; 316b7653853SJakob Hauser } 317b7653853SJakob Hauser 318b7653853SJakob Hauser ret = rt5033_init_pre_charge(charger); 319b7653853SJakob Hauser if (ret) 320b7653853SJakob Hauser return ret; 321b7653853SJakob Hauser 322b7653853SJakob Hauser ret = rt5033_init_fast_charge(charger); 323b7653853SJakob Hauser if (ret) 324b7653853SJakob Hauser return ret; 325b7653853SJakob Hauser 326b7653853SJakob Hauser ret = rt5033_init_const_charge(charger); 327b7653853SJakob Hauser if (ret) 328b7653853SJakob Hauser return ret; 329b7653853SJakob Hauser 330b7653853SJakob Hauser return 0; 331b7653853SJakob Hauser } 332b7653853SJakob Hauser 333b7653853SJakob Hauser static enum power_supply_property rt5033_charger_props[] = { 334b7653853SJakob Hauser POWER_SUPPLY_PROP_STATUS, 335b7653853SJakob Hauser POWER_SUPPLY_PROP_CHARGE_TYPE, 336b7653853SJakob Hauser POWER_SUPPLY_PROP_CURRENT_MAX, 337b7653853SJakob Hauser POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 338b7653853SJakob Hauser POWER_SUPPLY_PROP_MODEL_NAME, 339b7653853SJakob Hauser POWER_SUPPLY_PROP_MANUFACTURER, 340b7653853SJakob Hauser POWER_SUPPLY_PROP_ONLINE, 341b7653853SJakob Hauser }; 342b7653853SJakob Hauser 343b7653853SJakob Hauser static int rt5033_charger_get_property(struct power_supply *psy, 344b7653853SJakob Hauser enum power_supply_property psp, 345b7653853SJakob Hauser union power_supply_propval *val) 346b7653853SJakob Hauser { 347b7653853SJakob Hauser struct rt5033_charger *charger = power_supply_get_drvdata(psy); 348b7653853SJakob Hauser 349b7653853SJakob Hauser switch (psp) { 350b7653853SJakob Hauser case POWER_SUPPLY_PROP_STATUS: 351b7653853SJakob Hauser val->intval = rt5033_get_charger_state(charger); 352b7653853SJakob Hauser break; 353b7653853SJakob Hauser case POWER_SUPPLY_PROP_CHARGE_TYPE: 354b7653853SJakob Hauser val->intval = rt5033_get_charger_type(charger); 355b7653853SJakob Hauser break; 356b7653853SJakob Hauser case POWER_SUPPLY_PROP_CURRENT_MAX: 357b7653853SJakob Hauser val->intval = rt5033_get_charger_current_limit(charger); 358b7653853SJakob Hauser break; 359b7653853SJakob Hauser case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 360b7653853SJakob Hauser val->intval = rt5033_get_charger_const_voltage(charger); 361b7653853SJakob Hauser break; 362b7653853SJakob Hauser case POWER_SUPPLY_PROP_MODEL_NAME: 363b7653853SJakob Hauser val->strval = RT5033_CHARGER_MODEL; 364b7653853SJakob Hauser break; 365b7653853SJakob Hauser case POWER_SUPPLY_PROP_MANUFACTURER: 366b7653853SJakob Hauser val->strval = RT5033_MANUFACTURER; 367b7653853SJakob Hauser break; 368b7653853SJakob Hauser case POWER_SUPPLY_PROP_ONLINE: 369b7653853SJakob Hauser val->intval = (rt5033_get_charger_state(charger) == 370b7653853SJakob Hauser POWER_SUPPLY_STATUS_CHARGING); 371b7653853SJakob Hauser break; 372b7653853SJakob Hauser default: 373b7653853SJakob Hauser return -EINVAL; 374b7653853SJakob Hauser } 375b7653853SJakob Hauser 376b7653853SJakob Hauser return 0; 377b7653853SJakob Hauser } 378b7653853SJakob Hauser 379b7653853SJakob Hauser static struct rt5033_charger_data *rt5033_charger_dt_init( 380b7653853SJakob Hauser struct rt5033_charger *charger) 381b7653853SJakob Hauser { 382b7653853SJakob Hauser struct rt5033_charger_data *chg; 383b7653853SJakob Hauser struct power_supply_battery_info *info; 384b7653853SJakob Hauser int ret; 385b7653853SJakob Hauser 386b7653853SJakob Hauser chg = devm_kzalloc(charger->dev, sizeof(*chg), GFP_KERNEL); 387b7653853SJakob Hauser if (!chg) 388b7653853SJakob Hauser return ERR_PTR(-ENOMEM); 389b7653853SJakob Hauser 390b7653853SJakob Hauser ret = power_supply_get_battery_info(charger->psy, &info); 391b7653853SJakob Hauser if (ret) 392b7653853SJakob Hauser return ERR_PTR(dev_err_probe(charger->dev, -EINVAL, 393b7653853SJakob Hauser "missing battery info\n")); 394b7653853SJakob Hauser 395b7653853SJakob Hauser /* Assign data. Validity will be checked in the init functions. */ 396b7653853SJakob Hauser chg->pre_uamp = info->precharge_current_ua; 397b7653853SJakob Hauser chg->fast_uamp = info->constant_charge_current_max_ua; 398b7653853SJakob Hauser chg->eoc_uamp = info->charge_term_current_ua; 399b7653853SJakob Hauser chg->pre_uvolt = info->precharge_voltage_max_uv; 400b7653853SJakob Hauser chg->const_uvolt = info->constant_charge_voltage_max_uv; 401b7653853SJakob Hauser 402b7653853SJakob Hauser return chg; 403b7653853SJakob Hauser } 404b7653853SJakob Hauser 405b7653853SJakob Hauser static const struct power_supply_desc rt5033_charger_desc = { 406b7653853SJakob Hauser .name = "rt5033-charger", 407b7653853SJakob Hauser .type = POWER_SUPPLY_TYPE_USB, 408b7653853SJakob Hauser .properties = rt5033_charger_props, 409b7653853SJakob Hauser .num_properties = ARRAY_SIZE(rt5033_charger_props), 410b7653853SJakob Hauser .get_property = rt5033_charger_get_property, 411b7653853SJakob Hauser }; 412b7653853SJakob Hauser 413b7653853SJakob Hauser static int rt5033_charger_probe(struct platform_device *pdev) 414b7653853SJakob Hauser { 415b7653853SJakob Hauser struct rt5033_charger *charger; 416b7653853SJakob Hauser struct power_supply_config psy_cfg = {}; 417b7653853SJakob Hauser int ret; 418b7653853SJakob Hauser 419b7653853SJakob Hauser charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); 420b7653853SJakob Hauser if (!charger) 421b7653853SJakob Hauser return -ENOMEM; 422b7653853SJakob Hauser 423b7653853SJakob Hauser platform_set_drvdata(pdev, charger); 424b7653853SJakob Hauser charger->dev = &pdev->dev; 425b7653853SJakob Hauser charger->regmap = dev_get_regmap(pdev->dev.parent, NULL); 426b7653853SJakob Hauser 427b7653853SJakob Hauser psy_cfg.of_node = pdev->dev.of_node; 428b7653853SJakob Hauser psy_cfg.drv_data = charger; 429b7653853SJakob Hauser 430b7653853SJakob Hauser charger->psy = devm_power_supply_register(&pdev->dev, 431b7653853SJakob Hauser &rt5033_charger_desc, 432b7653853SJakob Hauser &psy_cfg); 433b7653853SJakob Hauser if (IS_ERR(charger->psy)) 434b7653853SJakob Hauser return dev_err_probe(&pdev->dev, PTR_ERR(charger->psy), 435b7653853SJakob Hauser "Failed to register power supply\n"); 436b7653853SJakob Hauser 437b7653853SJakob Hauser charger->chg = rt5033_charger_dt_init(charger); 438b7653853SJakob Hauser if (IS_ERR_OR_NULL(charger->chg)) 439b7653853SJakob Hauser return PTR_ERR(charger->chg); 440b7653853SJakob Hauser 441b7653853SJakob Hauser ret = rt5033_charger_reg_init(charger); 442b7653853SJakob Hauser if (ret) 443b7653853SJakob Hauser return ret; 444b7653853SJakob Hauser 445b7653853SJakob Hauser return 0; 446b7653853SJakob Hauser } 447b7653853SJakob Hauser 448b7653853SJakob Hauser static const struct platform_device_id rt5033_charger_id[] = { 449b7653853SJakob Hauser { "rt5033-charger", }, 450b7653853SJakob Hauser { } 451b7653853SJakob Hauser }; 452b7653853SJakob Hauser MODULE_DEVICE_TABLE(platform, rt5033_charger_id); 453b7653853SJakob Hauser 454b7653853SJakob Hauser static const struct of_device_id rt5033_charger_of_match[] = { 455b7653853SJakob Hauser { .compatible = "richtek,rt5033-charger", }, 456b7653853SJakob Hauser { } 457b7653853SJakob Hauser }; 458b7653853SJakob Hauser MODULE_DEVICE_TABLE(of, rt5033_charger_of_match); 459b7653853SJakob Hauser 460b7653853SJakob Hauser static struct platform_driver rt5033_charger_driver = { 461b7653853SJakob Hauser .driver = { 462b7653853SJakob Hauser .name = "rt5033-charger", 463b7653853SJakob Hauser .of_match_table = rt5033_charger_of_match, 464b7653853SJakob Hauser }, 465b7653853SJakob Hauser .probe = rt5033_charger_probe, 466b7653853SJakob Hauser .id_table = rt5033_charger_id, 467b7653853SJakob Hauser }; 468b7653853SJakob Hauser module_platform_driver(rt5033_charger_driver); 469b7653853SJakob Hauser 470b7653853SJakob Hauser MODULE_DESCRIPTION("Richtek RT5033 charger driver"); 471b7653853SJakob Hauser MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); 472b7653853SJakob Hauser MODULE_LICENSE("GPL v2"); 473