root/drivers/power/supply/max77650-charger.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. max77650_charger_set_vchgin_min
  2. max77650_charger_set_ichgin_lim
  3. max77650_charger_enable
  4. max77650_charger_disable
  5. max77650_charger_check_status
  6. max77650_charger_get_property
  7. max77650_charger_probe
  8. max77650_charger_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 //
   3 // Copyright (C) 2018 BayLibre SAS
   4 // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
   5 //
   6 // Battery charger driver for MAXIM 77650/77651 charger/power-supply.
   7 
   8 #include <linux/i2c.h>
   9 #include <linux/interrupt.h>
  10 #include <linux/mfd/max77650.h>
  11 #include <linux/module.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/power_supply.h>
  14 #include <linux/regmap.h>
  15 
  16 #define MAX77650_CHARGER_ENABLED                BIT(0)
  17 #define MAX77650_CHARGER_DISABLED               0x00
  18 #define MAX77650_CHARGER_CHG_EN_MASK            BIT(0)
  19 
  20 #define MAX77650_CHG_DETAILS_MASK               GENMASK(7, 4)
  21 #define MAX77650_CHG_DETAILS_BITS(_reg) \
  22                 (((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4)
  23 
  24 /* Charger is OFF. */
  25 #define MAX77650_CHG_OFF                        0x00
  26 /* Charger is in prequalification mode. */
  27 #define MAX77650_CHG_PREQ                       0x01
  28 /* Charger is in fast-charge constant current mode. */
  29 #define MAX77650_CHG_ON_CURR                    0x02
  30 /* Charger is in JEITA modified fast-charge constant-current mode. */
  31 #define MAX77650_CHG_ON_CURR_JEITA              0x03
  32 /* Charger is in fast-charge constant-voltage mode. */
  33 #define MAX77650_CHG_ON_VOLT                    0x04
  34 /* Charger is in JEITA modified fast-charge constant-voltage mode. */
  35 #define MAX77650_CHG_ON_VOLT_JEITA              0x05
  36 /* Charger is in top-off mode. */
  37 #define MAX77650_CHG_ON_TOPOFF                  0x06
  38 /* Charger is in JEITA modified top-off mode. */
  39 #define MAX77650_CHG_ON_TOPOFF_JEITA            0x07
  40 /* Charger is done. */
  41 #define MAX77650_CHG_DONE                       0x08
  42 /* Charger is JEITA modified done. */
  43 #define MAX77650_CHG_DONE_JEITA                 0x09
  44 /* Charger is suspended due to a prequalification timer fault. */
  45 #define MAX77650_CHG_SUSP_PREQ_TIM_FAULT        0x0a
  46 /* Charger is suspended due to a fast-charge timer fault. */
  47 #define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT    0x0b
  48 /* Charger is suspended due to a battery temperature fault. */
  49 #define MAX77650_CHG_SUSP_BATT_TEMP_FAULT       0x0c
  50 
  51 #define MAX77650_CHGIN_DETAILS_MASK             GENMASK(3, 2)
  52 #define MAX77650_CHGIN_DETAILS_BITS(_reg) \
  53                 (((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2)
  54 
  55 #define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT     0x00
  56 #define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT      0x01
  57 #define MAX77650_CHGIN_OKAY                     0x11
  58 
  59 #define MAX77650_CHARGER_CHG_MASK       BIT(1)
  60 #define MAX77650_CHARGER_CHG_CHARGING(_reg) \
  61                 (((_reg) & MAX77650_CHARGER_CHG_MASK) > 1)
  62 
  63 #define MAX77650_CHARGER_VCHGIN_MIN_MASK        0xc0
  64 #define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val) ((_val) << 5)
  65 
  66 #define MAX77650_CHARGER_ICHGIN_LIM_MASK        0x1c
  67 #define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val) ((_val) << 2)
  68 
  69 struct max77650_charger_data {
  70         struct regmap *map;
  71         struct device *dev;
  72 };
  73 
  74 static enum power_supply_property max77650_charger_properties[] = {
  75         POWER_SUPPLY_PROP_STATUS,
  76         POWER_SUPPLY_PROP_ONLINE,
  77         POWER_SUPPLY_PROP_CHARGE_TYPE
  78 };
  79 
  80 static const unsigned int max77650_charger_vchgin_min_table[] = {
  81         4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000
  82 };
  83 
  84 static const unsigned int max77650_charger_ichgin_lim_table[] = {
  85         95000, 190000, 285000, 380000, 475000
  86 };
  87 
  88 static int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg,
  89                                            unsigned int val)
  90 {
  91         int i, rv;
  92 
  93         for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) {
  94                 if (val == max77650_charger_vchgin_min_table[i]) {
  95                         rv = regmap_update_bits(chg->map,
  96                                         MAX77650_REG_CNFG_CHG_B,
  97                                         MAX77650_CHARGER_VCHGIN_MIN_MASK,
  98                                         MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i));
  99                         if (rv)
 100                                 return rv;
 101 
 102                         return 0;
 103                 }
 104         }
 105 
 106         return -EINVAL;
 107 }
 108 
 109 static int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg,
 110                                            unsigned int val)
 111 {
 112         int i, rv;
 113 
 114         for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) {
 115                 if (val == max77650_charger_ichgin_lim_table[i]) {
 116                         rv = regmap_update_bits(chg->map,
 117                                         MAX77650_REG_CNFG_CHG_B,
 118                                         MAX77650_CHARGER_ICHGIN_LIM_MASK,
 119                                         MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i));
 120                         if (rv)
 121                                 return rv;
 122 
 123                         return 0;
 124                 }
 125         }
 126 
 127         return -EINVAL;
 128 }
 129 
 130 static int max77650_charger_enable(struct max77650_charger_data *chg)
 131 {
 132         int rv;
 133 
 134         rv = regmap_update_bits(chg->map,
 135                                 MAX77650_REG_CNFG_CHG_B,
 136                                 MAX77650_CHARGER_CHG_EN_MASK,
 137                                 MAX77650_CHARGER_ENABLED);
 138         if (rv)
 139                 dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
 140 
 141         return rv;
 142 }
 143 
 144 static int max77650_charger_disable(struct max77650_charger_data *chg)
 145 {
 146         int rv;
 147 
 148         rv = regmap_update_bits(chg->map,
 149                                 MAX77650_REG_CNFG_CHG_B,
 150                                 MAX77650_CHARGER_CHG_EN_MASK,
 151                                 MAX77650_CHARGER_DISABLED);
 152         if (rv)
 153                 dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
 154 
 155         return rv;
 156 }
 157 
 158 static irqreturn_t max77650_charger_check_status(int irq, void *data)
 159 {
 160         struct max77650_charger_data *chg = data;
 161         int rv, reg;
 162 
 163         rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
 164         if (rv) {
 165                 dev_err(chg->dev,
 166                         "unable to read the charger status: %d\n", rv);
 167                 return IRQ_HANDLED;
 168         }
 169 
 170         switch (MAX77650_CHGIN_DETAILS_BITS(reg)) {
 171         case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT:
 172                 dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n");
 173                 max77650_charger_disable(chg);
 174                 break;
 175         case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT:
 176                 dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n");
 177                 max77650_charger_disable(chg);
 178                 break;
 179         case MAX77650_CHGIN_OKAY:
 180                 max77650_charger_enable(chg);
 181                 break;
 182         default:
 183                 /* May be 0x10 - debouncing */
 184                 break;
 185         }
 186 
 187         return IRQ_HANDLED;
 188 }
 189 
 190 static int max77650_charger_get_property(struct power_supply *psy,
 191                                          enum power_supply_property psp,
 192                                          union power_supply_propval *val)
 193 {
 194         struct max77650_charger_data *chg = power_supply_get_drvdata(psy);
 195         int rv, reg;
 196 
 197         switch (psp) {
 198         case POWER_SUPPLY_PROP_STATUS:
 199                 rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
 200                 if (rv)
 201                         return rv;
 202 
 203                 if (MAX77650_CHARGER_CHG_CHARGING(reg)) {
 204                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
 205                         break;
 206                 }
 207 
 208                 switch (MAX77650_CHG_DETAILS_BITS(reg)) {
 209                 case MAX77650_CHG_OFF:
 210                 case MAX77650_CHG_SUSP_PREQ_TIM_FAULT:
 211                 case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT:
 212                 case MAX77650_CHG_SUSP_BATT_TEMP_FAULT:
 213                         val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 214                         break;
 215                 case MAX77650_CHG_PREQ:
 216                 case MAX77650_CHG_ON_CURR:
 217                 case MAX77650_CHG_ON_CURR_JEITA:
 218                 case MAX77650_CHG_ON_VOLT:
 219                 case MAX77650_CHG_ON_VOLT_JEITA:
 220                 case MAX77650_CHG_ON_TOPOFF:
 221                 case MAX77650_CHG_ON_TOPOFF_JEITA:
 222                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
 223                         break;
 224                 case MAX77650_CHG_DONE:
 225                         val->intval = POWER_SUPPLY_STATUS_FULL;
 226                         break;
 227                 default:
 228                         val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
 229                 }
 230                 break;
 231         case POWER_SUPPLY_PROP_ONLINE:
 232                 rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
 233                 if (rv)
 234                         return rv;
 235 
 236                 val->intval = MAX77650_CHARGER_CHG_CHARGING(reg);
 237                 break;
 238         case POWER_SUPPLY_PROP_CHARGE_TYPE:
 239                 rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
 240                 if (rv)
 241                         return rv;
 242 
 243                 if (!MAX77650_CHARGER_CHG_CHARGING(reg)) {
 244                         val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
 245                         break;
 246                 }
 247 
 248                 switch (MAX77650_CHG_DETAILS_BITS(reg)) {
 249                 case MAX77650_CHG_PREQ:
 250                 case MAX77650_CHG_ON_CURR:
 251                 case MAX77650_CHG_ON_CURR_JEITA:
 252                 case MAX77650_CHG_ON_VOLT:
 253                 case MAX77650_CHG_ON_VOLT_JEITA:
 254                         val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
 255                         break;
 256                 case MAX77650_CHG_ON_TOPOFF:
 257                 case MAX77650_CHG_ON_TOPOFF_JEITA:
 258                         val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
 259                         break;
 260                 default:
 261                         val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
 262                 }
 263                 break;
 264         default:
 265                 return -EINVAL;
 266         }
 267 
 268         return 0;
 269 }
 270 
 271 static const struct power_supply_desc max77650_battery_desc = {
 272         .name           = "max77650",
 273         .type           = POWER_SUPPLY_TYPE_USB,
 274         .get_property   = max77650_charger_get_property,
 275         .properties     = max77650_charger_properties,
 276         .num_properties = ARRAY_SIZE(max77650_charger_properties),
 277 };
 278 
 279 static int max77650_charger_probe(struct platform_device *pdev)
 280 {
 281         struct power_supply_config pscfg = {};
 282         struct max77650_charger_data *chg;
 283         struct power_supply *battery;
 284         struct device *dev, *parent;
 285         int rv, chg_irq, chgin_irq;
 286         unsigned int prop;
 287 
 288         dev = &pdev->dev;
 289         parent = dev->parent;
 290 
 291         chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
 292         if (!chg)
 293                 return -ENOMEM;
 294 
 295         platform_set_drvdata(pdev, chg);
 296 
 297         chg->map = dev_get_regmap(parent, NULL);
 298         if (!chg->map)
 299                 return -ENODEV;
 300 
 301         chg->dev = dev;
 302 
 303         pscfg.of_node = dev->of_node;
 304         pscfg.drv_data = chg;
 305 
 306         chg_irq = platform_get_irq_byname(pdev, "CHG");
 307         if (chg_irq < 0)
 308                 return chg_irq;
 309 
 310         chgin_irq = platform_get_irq_byname(pdev, "CHGIN");
 311         if (chgin_irq < 0)
 312                 return chgin_irq;
 313 
 314         rv = devm_request_any_context_irq(dev, chg_irq,
 315                                           max77650_charger_check_status,
 316                                           IRQF_ONESHOT, "chg", chg);
 317         if (rv < 0)
 318                 return rv;
 319 
 320         rv = devm_request_any_context_irq(dev, chgin_irq,
 321                                           max77650_charger_check_status,
 322                                           IRQF_ONESHOT, "chgin", chg);
 323         if (rv < 0)
 324                 return rv;
 325 
 326         battery = devm_power_supply_register(dev,
 327                                              &max77650_battery_desc, &pscfg);
 328         if (IS_ERR(battery))
 329                 return PTR_ERR(battery);
 330 
 331         rv = of_property_read_u32(dev->of_node,
 332                                   "input-voltage-min-microvolt", &prop);
 333         if (rv == 0) {
 334                 rv = max77650_charger_set_vchgin_min(chg, prop);
 335                 if (rv)
 336                         return rv;
 337         }
 338 
 339         rv = of_property_read_u32(dev->of_node,
 340                                   "input-current-limit-microamp", &prop);
 341         if (rv == 0) {
 342                 rv = max77650_charger_set_ichgin_lim(chg, prop);
 343                 if (rv)
 344                         return rv;
 345         }
 346 
 347         return max77650_charger_enable(chg);
 348 }
 349 
 350 static int max77650_charger_remove(struct platform_device *pdev)
 351 {
 352         struct max77650_charger_data *chg = platform_get_drvdata(pdev);
 353 
 354         return max77650_charger_disable(chg);
 355 }
 356 
 357 static struct platform_driver max77650_charger_driver = {
 358         .driver = {
 359                 .name = "max77650-charger",
 360         },
 361         .probe = max77650_charger_probe,
 362         .remove = max77650_charger_remove,
 363 };
 364 module_platform_driver(max77650_charger_driver);
 365 
 366 MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver");
 367 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
 368 MODULE_LICENSE("GPL v2");
 369 MODULE_ALIAS("platform:max77650-charger");

/* [<][>][^][v][top][bottom][index][help] */