Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power_supply: Add charger support for Maxim 14577

MAX14577 chip is a multi-function device which includes MUIC, charger and
voltage regulator. The driver is located in drivers/mfd.

This patch supports battery charging control of MAX14577 chip and provides
power supply class information to userspace.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Anton Vorontsov <anton@enomsg.org>

authored by

Krzysztof Kozlowski and committed by
Anton Vorontsov
55e64701 fac171ac

+319
+7
drivers/power/Kconfig
··· 317 317 runtime and in suspend-to-RAM by waking up the system periodically 318 318 with help of suspend_again support. 319 319 320 + config CHARGER_MAX14577 321 + tristate "Maxim MAX14577 MUIC battery charger driver" 322 + depends on MFD_MAX14577 323 + help 324 + Say Y to enable support for the battery charger control sysfs and 325 + platform data of MAX14577 MUICs. 326 + 320 327 config CHARGER_MAX8997 321 328 tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" 322 329 depends on MFD_MAX8997 && REGULATOR_MAX8997
+1
drivers/power/Makefile
··· 48 48 obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o 49 49 obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o 50 50 obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o 51 + obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o 51 52 obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o 52 53 obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o 53 54 obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
+311
drivers/power/max14577_charger.c
··· 1 + /* 2 + * Battery charger driver for the Maxim 14577 3 + * 4 + * Copyright (C) 2013 Samsung Electronics 5 + * Krzysztof Kozlowski <k.kozlowski@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/power_supply.h> 21 + #include <linux/mfd/max14577-private.h> 22 + 23 + struct max14577_charger { 24 + struct device *dev; 25 + struct max14577 *max14577; 26 + struct power_supply charger; 27 + 28 + unsigned int charging_state; 29 + unsigned int battery_state; 30 + }; 31 + 32 + static int max14577_get_charger_state(struct max14577_charger *chg) 33 + { 34 + struct regmap *rmap = chg->max14577->regmap; 35 + int state = POWER_SUPPLY_STATUS_DISCHARGING; 36 + u8 reg_data; 37 + 38 + /* 39 + * Charging occurs only if: 40 + * - CHGCTRL2/MBCHOSTEN == 1 41 + * - STATUS2/CGMBC == 1 42 + * 43 + * TODO: 44 + * - handle FULL after Top-off timer (EOC register may be off 45 + * and the charger won't be charging although MBCHOSTEN is on) 46 + * - handle properly dead-battery charging (respect timer) 47 + * - handle timers (fast-charge and prequal) /MBCCHGERR/ 48 + */ 49 + max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL2, &reg_data); 50 + if ((reg_data & CHGCTRL2_MBCHOSTEN_MASK) == 0) 51 + goto state_set; 52 + 53 + max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, &reg_data); 54 + if (reg_data & STATUS3_CGMBC_MASK) { 55 + /* Charger or USB-cable is connected */ 56 + if (reg_data & STATUS3_EOC_MASK) 57 + state = POWER_SUPPLY_STATUS_FULL; 58 + else 59 + state = POWER_SUPPLY_STATUS_CHARGING; 60 + goto state_set; 61 + } 62 + 63 + state_set: 64 + chg->charging_state = state; 65 + return state; 66 + } 67 + 68 + /* 69 + * Supported charge types: 70 + * - POWER_SUPPLY_CHARGE_TYPE_NONE 71 + * - POWER_SUPPLY_CHARGE_TYPE_FAST 72 + */ 73 + static int max14577_get_charge_type(struct max14577_charger *chg) 74 + { 75 + /* 76 + * TODO: CHARGE_TYPE_TRICKLE (VCHGR_RC or EOC)? 77 + * As spec says: 78 + * [after reaching EOC interrupt] 79 + * "When the battery is fully charged, the 30-minute (typ) 80 + * top-off timer starts. The device continues to trickle 81 + * charge the battery until the top-off timer runs out." 82 + */ 83 + if (max14577_get_charger_state(chg) == POWER_SUPPLY_STATUS_CHARGING) 84 + return POWER_SUPPLY_CHARGE_TYPE_FAST; 85 + return POWER_SUPPLY_CHARGE_TYPE_NONE; 86 + } 87 + 88 + static int max14577_get_online(struct max14577_charger *chg) 89 + { 90 + struct regmap *rmap = chg->max14577->regmap; 91 + u8 reg_data; 92 + 93 + max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, &reg_data); 94 + reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT); 95 + switch (reg_data) { 96 + case MAX14577_CHARGER_TYPE_USB: 97 + case MAX14577_CHARGER_TYPE_DEDICATED_CHG: 98 + case MAX14577_CHARGER_TYPE_SPECIAL_500MA: 99 + case MAX14577_CHARGER_TYPE_SPECIAL_1A: 100 + case MAX14577_CHARGER_TYPE_DEAD_BATTERY: 101 + return 1; 102 + case MAX14577_CHARGER_TYPE_NONE: 103 + case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT: 104 + case MAX14577_CHARGER_TYPE_RESERVED: 105 + default: 106 + return 0; 107 + } 108 + } 109 + 110 + /* 111 + * Supported health statuses: 112 + * - POWER_SUPPLY_HEALTH_DEAD 113 + * - POWER_SUPPLY_HEALTH_OVERVOLTAGE 114 + * - POWER_SUPPLY_HEALTH_GOOD 115 + */ 116 + static int max14577_get_battery_health(struct max14577_charger *chg) 117 + { 118 + struct regmap *rmap = chg->max14577->regmap; 119 + int state = POWER_SUPPLY_HEALTH_GOOD; 120 + u8 reg_data; 121 + 122 + max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, &reg_data); 123 + reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT); 124 + if (reg_data == MAX14577_CHARGER_TYPE_DEAD_BATTERY) { 125 + state = POWER_SUPPLY_HEALTH_DEAD; 126 + goto state_set; 127 + } 128 + 129 + max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, &reg_data); 130 + if (reg_data & STATUS3_OVP_MASK) { 131 + state = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 132 + goto state_set; 133 + } 134 + 135 + state_set: 136 + chg->battery_state = state; 137 + return state; 138 + } 139 + 140 + /* 141 + * Always returns 1. 142 + * The max14577 chip doesn't report any status of battery presence. 143 + * Lets assume that it will always be used with some battery. 144 + */ 145 + static int max14577_get_present(struct max14577_charger *chg) 146 + { 147 + return 1; 148 + } 149 + 150 + /* 151 + * Sets charger registers to proper and safe default values. 152 + * Some of these values are equal to defaults in MAX14577E 153 + * data sheet but there are minor differences. 154 + */ 155 + static void max14577_charger_reg_init(struct max14577_charger *chg) 156 + { 157 + struct regmap *rmap = chg->max14577->regmap; 158 + u8 reg_data; 159 + 160 + /* 161 + * Charger-Type Manual Detection, default off (set CHGTYPMAN to 0) 162 + * Charger-Detection Enable, default on (set CHGDETEN to 1) 163 + * Combined mask of CHGDETEN and CHGTYPMAN will zero the CHGTYPMAN bit 164 + */ 165 + reg_data = 0x1 << CDETCTRL1_CHGDETEN_SHIFT; 166 + max14577_update_reg(rmap, MAX14577_REG_CDETCTRL1, 167 + CDETCTRL1_CHGDETEN_MASK | CDETCTRL1_CHGTYPMAN_MASK, 168 + reg_data); 169 + 170 + /* Battery Fast-Charge Timer, from SM-V700: 6hrs */ 171 + reg_data = 0x3 << CHGCTRL1_TCHW_SHIFT; 172 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL1, reg_data); 173 + 174 + /* 175 + * Wall-Adapter Rapid Charge, default on 176 + * Battery-Charger, default on 177 + */ 178 + reg_data = 0x1 << CHGCTRL2_VCHGR_RC_SHIFT; 179 + reg_data |= 0x1 << CHGCTRL2_MBCHOSTEN_SHIFT; 180 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL2, reg_data); 181 + 182 + /* Battery-Charger Constant Voltage (CV) Mode, from SM-V700: 4.35V */ 183 + reg_data = 0xf << CHGCTRL3_MBCCVWRC_SHIFT; 184 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL3, reg_data); 185 + 186 + /* 187 + * Fast Battery-Charge Current Low, default 200-950mA 188 + * Fast Battery-Charge Current High, from SM-V700: 450mA 189 + */ 190 + reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT; 191 + reg_data |= 0x5 << CHGCTRL4_MBCICHWRCH_SHIFT; 192 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL4, reg_data); 193 + 194 + /* End-of-Charge Current, from SM-V700: 50mA */ 195 + reg_data = 0x0 << CHGCTRL5_EOCS_SHIFT; 196 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL5, reg_data); 197 + 198 + /* Auto Charging Stop, default off */ 199 + reg_data = 0x0 << CHGCTRL6_AUTOSTOP_SHIFT; 200 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL6, reg_data); 201 + 202 + /* Overvoltage-Protection Threshold, from SM-V700: 6.5V */ 203 + reg_data = 0x2 << CHGCTRL7_OTPCGHCVS_SHIFT; 204 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL7, reg_data); 205 + } 206 + 207 + /* Support property from charger */ 208 + static enum power_supply_property max14577_charger_props[] = { 209 + POWER_SUPPLY_PROP_STATUS, 210 + POWER_SUPPLY_PROP_CHARGE_TYPE, 211 + POWER_SUPPLY_PROP_HEALTH, 212 + POWER_SUPPLY_PROP_PRESENT, 213 + POWER_SUPPLY_PROP_ONLINE, 214 + POWER_SUPPLY_PROP_MODEL_NAME, 215 + POWER_SUPPLY_PROP_MANUFACTURER, 216 + }; 217 + 218 + static const char *model_name = "MAX14577"; 219 + static const char *manufacturer = "Maxim Integrated"; 220 + 221 + static int max14577_charger_get_property(struct power_supply *psy, 222 + enum power_supply_property psp, 223 + union power_supply_propval *val) 224 + { 225 + struct max14577_charger *chg = container_of(psy, 226 + struct max14577_charger, 227 + charger); 228 + int ret = 0; 229 + 230 + switch (psp) { 231 + case POWER_SUPPLY_PROP_STATUS: 232 + val->intval = max14577_get_charger_state(chg); 233 + break; 234 + case POWER_SUPPLY_PROP_CHARGE_TYPE: 235 + val->intval = max14577_get_charge_type(chg); 236 + break; 237 + case POWER_SUPPLY_PROP_HEALTH: 238 + val->intval = max14577_get_battery_health(chg); 239 + break; 240 + case POWER_SUPPLY_PROP_PRESENT: 241 + val->intval = max14577_get_present(chg); 242 + break; 243 + case POWER_SUPPLY_PROP_ONLINE: 244 + val->intval = max14577_get_online(chg); 245 + break; 246 + case POWER_SUPPLY_PROP_MODEL_NAME: 247 + val->strval = model_name; 248 + break; 249 + case POWER_SUPPLY_PROP_MANUFACTURER: 250 + val->strval = manufacturer; 251 + break; 252 + default: 253 + return -EINVAL; 254 + } 255 + 256 + return ret; 257 + } 258 + 259 + static int max14577_charger_probe(struct platform_device *pdev) 260 + { 261 + struct max14577_charger *chg; 262 + struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); 263 + int ret; 264 + 265 + chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); 266 + if (!chg) 267 + return -ENOMEM; 268 + 269 + platform_set_drvdata(pdev, chg); 270 + chg->dev = &pdev->dev; 271 + chg->max14577 = max14577; 272 + 273 + max14577_charger_reg_init(chg); 274 + 275 + chg->charger.name = "max14577-charger", 276 + chg->charger.type = POWER_SUPPLY_TYPE_BATTERY, 277 + chg->charger.properties = max14577_charger_props, 278 + chg->charger.num_properties = ARRAY_SIZE(max14577_charger_props), 279 + chg->charger.get_property = max14577_charger_get_property, 280 + 281 + ret = power_supply_register(&pdev->dev, &chg->charger); 282 + if (ret) { 283 + dev_err(&pdev->dev, "failed: power supply register\n"); 284 + return ret; 285 + } 286 + 287 + return 0; 288 + } 289 + 290 + static int max14577_charger_remove(struct platform_device *pdev) 291 + { 292 + struct max14577_charger *chg = platform_get_drvdata(pdev); 293 + 294 + power_supply_unregister(&chg->charger); 295 + 296 + return 0; 297 + } 298 + 299 + static struct platform_driver max14577_charger_driver = { 300 + .driver = { 301 + .owner = THIS_MODULE, 302 + .name = "max14577-charger", 303 + }, 304 + .probe = max14577_charger_probe, 305 + .remove = max14577_charger_remove, 306 + }; 307 + module_platform_driver(max14577_charger_driver); 308 + 309 + MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>"); 310 + MODULE_DESCRIPTION("MAXIM 14577 charger driver"); 311 + MODULE_LICENSE("GPL");