1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // max17040_battery.c 4 // fuel-gauge systems for lithium-ion (Li+) batteries 5 // 6 // Copyright (C) 2009 Samsung Electronics 7 // Minkyu Kang <mk7.kang@samsung.com> 8 9 #include <linux/module.h> 10 #include <linux/init.h> 11 #include <linux/platform_device.h> 12 #include <linux/mutex.h> 13 #include <linux/err.h> 14 #include <linux/i2c.h> 15 #include <linux/delay.h> 16 #include <linux/power_supply.h> 17 #include <linux/max17040_battery.h> 18 #include <linux/slab.h> 19 20 #define MAX17040_VCELL 0x02 21 #define MAX17040_SOC 0x04 22 #define MAX17040_MODE 0x06 23 #define MAX17040_VER 0x08 24 #define MAX17040_RCOMP 0x0C 25 #define MAX17040_CMD 0xFE 26 27 28 #define MAX17040_DELAY 1000 29 #define MAX17040_BATTERY_FULL 95 30 31 struct max17040_chip { 32 struct i2c_client *client; 33 struct delayed_work work; 34 struct power_supply *battery; 35 struct max17040_platform_data *pdata; 36 37 /* State Of Connect */ 38 int online; 39 /* battery voltage */ 40 int vcell; 41 /* battery capacity */ 42 int soc; 43 /* State Of Charge */ 44 int status; 45 }; 46 47 static int max17040_get_property(struct power_supply *psy, 48 enum power_supply_property psp, 49 union power_supply_propval *val) 50 { 51 struct max17040_chip *chip = power_supply_get_drvdata(psy); 52 53 switch (psp) { 54 case POWER_SUPPLY_PROP_STATUS: 55 val->intval = chip->status; 56 break; 57 case POWER_SUPPLY_PROP_ONLINE: 58 val->intval = chip->online; 59 break; 60 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 61 val->intval = chip->vcell; 62 break; 63 case POWER_SUPPLY_PROP_CAPACITY: 64 val->intval = chip->soc; 65 break; 66 default: 67 return -EINVAL; 68 } 69 return 0; 70 } 71 72 static int max17040_write_reg(struct i2c_client *client, int reg, u16 value) 73 { 74 int ret; 75 76 ret = i2c_smbus_write_word_swapped(client, reg, value); 77 78 if (ret < 0) 79 dev_err(&client->dev, "%s: err %d\n", __func__, ret); 80 81 return ret; 82 } 83 84 static int max17040_read_reg(struct i2c_client *client, int reg) 85 { 86 int ret; 87 88 ret = i2c_smbus_read_word_swapped(client, reg); 89 90 if (ret < 0) 91 dev_err(&client->dev, "%s: err %d\n", __func__, ret); 92 93 return ret; 94 } 95 96 static void max17040_reset(struct i2c_client *client) 97 { 98 max17040_write_reg(client, MAX17040_CMD, 0x0054); 99 } 100 101 static void max17040_get_vcell(struct i2c_client *client) 102 { 103 struct max17040_chip *chip = i2c_get_clientdata(client); 104 u16 vcell; 105 106 vcell = max17040_read_reg(client, MAX17040_VCELL); 107 108 chip->vcell = vcell; 109 } 110 111 static void max17040_get_soc(struct i2c_client *client) 112 { 113 struct max17040_chip *chip = i2c_get_clientdata(client); 114 u16 soc; 115 116 soc = max17040_read_reg(client, MAX17040_SOC); 117 118 chip->soc = (soc >> 8); 119 } 120 121 static void max17040_get_version(struct i2c_client *client) 122 { 123 u16 version; 124 125 version = max17040_read_reg(client, MAX17040_VER); 126 127 dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version); 128 } 129 130 static void max17040_get_online(struct i2c_client *client) 131 { 132 struct max17040_chip *chip = i2c_get_clientdata(client); 133 134 if (chip->pdata && chip->pdata->battery_online) 135 chip->online = chip->pdata->battery_online(); 136 else 137 chip->online = 1; 138 } 139 140 static void max17040_get_status(struct i2c_client *client) 141 { 142 struct max17040_chip *chip = i2c_get_clientdata(client); 143 144 if (!chip->pdata || !chip->pdata->charger_online 145 || !chip->pdata->charger_enable) { 146 chip->status = POWER_SUPPLY_STATUS_UNKNOWN; 147 return; 148 } 149 150 if (chip->pdata->charger_online()) { 151 if (chip->pdata->charger_enable()) 152 chip->status = POWER_SUPPLY_STATUS_CHARGING; 153 else 154 chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING; 155 } else { 156 chip->status = POWER_SUPPLY_STATUS_DISCHARGING; 157 } 158 159 if (chip->soc > MAX17040_BATTERY_FULL) 160 chip->status = POWER_SUPPLY_STATUS_FULL; 161 } 162 163 static void max17040_work(struct work_struct *work) 164 { 165 struct max17040_chip *chip; 166 167 chip = container_of(work, struct max17040_chip, work.work); 168 169 max17040_get_vcell(chip->client); 170 max17040_get_soc(chip->client); 171 max17040_get_online(chip->client); 172 max17040_get_status(chip->client); 173 174 queue_delayed_work(system_power_efficient_wq, &chip->work, 175 MAX17040_DELAY); 176 } 177 178 static enum power_supply_property max17040_battery_props[] = { 179 POWER_SUPPLY_PROP_STATUS, 180 POWER_SUPPLY_PROP_ONLINE, 181 POWER_SUPPLY_PROP_VOLTAGE_NOW, 182 POWER_SUPPLY_PROP_CAPACITY, 183 }; 184 185 static const struct power_supply_desc max17040_battery_desc = { 186 .name = "battery", 187 .type = POWER_SUPPLY_TYPE_BATTERY, 188 .get_property = max17040_get_property, 189 .properties = max17040_battery_props, 190 .num_properties = ARRAY_SIZE(max17040_battery_props), 191 }; 192 193 static int max17040_probe(struct i2c_client *client, 194 const struct i2c_device_id *id) 195 { 196 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 197 struct power_supply_config psy_cfg = {}; 198 struct max17040_chip *chip; 199 200 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) 201 return -EIO; 202 203 chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 204 if (!chip) 205 return -ENOMEM; 206 207 chip->client = client; 208 chip->pdata = client->dev.platform_data; 209 210 i2c_set_clientdata(client, chip); 211 psy_cfg.drv_data = chip; 212 213 chip->battery = power_supply_register(&client->dev, 214 &max17040_battery_desc, &psy_cfg); 215 if (IS_ERR(chip->battery)) { 216 dev_err(&client->dev, "failed: power supply register\n"); 217 return PTR_ERR(chip->battery); 218 } 219 220 max17040_reset(client); 221 max17040_get_version(client); 222 223 INIT_DEFERRABLE_WORK(&chip->work, max17040_work); 224 queue_delayed_work(system_power_efficient_wq, &chip->work, 225 MAX17040_DELAY); 226 227 return 0; 228 } 229 230 static int max17040_remove(struct i2c_client *client) 231 { 232 struct max17040_chip *chip = i2c_get_clientdata(client); 233 234 power_supply_unregister(chip->battery); 235 cancel_delayed_work(&chip->work); 236 return 0; 237 } 238 239 #ifdef CONFIG_PM_SLEEP 240 241 static int max17040_suspend(struct device *dev) 242 { 243 struct i2c_client *client = to_i2c_client(dev); 244 struct max17040_chip *chip = i2c_get_clientdata(client); 245 246 cancel_delayed_work(&chip->work); 247 return 0; 248 } 249 250 static int max17040_resume(struct device *dev) 251 { 252 struct i2c_client *client = to_i2c_client(dev); 253 struct max17040_chip *chip = i2c_get_clientdata(client); 254 255 queue_delayed_work(system_power_efficient_wq, &chip->work, 256 MAX17040_DELAY); 257 return 0; 258 } 259 260 static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume); 261 #define MAX17040_PM_OPS (&max17040_pm_ops) 262 263 #else 264 265 #define MAX17040_PM_OPS NULL 266 267 #endif /* CONFIG_PM_SLEEP */ 268 269 static const struct i2c_device_id max17040_id[] = { 270 { "max17040" }, 271 { "max77836-battery" }, 272 { } 273 }; 274 MODULE_DEVICE_TABLE(i2c, max17040_id); 275 276 static const struct of_device_id max17040_of_match[] = { 277 { .compatible = "maxim,max17040" }, 278 { .compatible = "maxim,max77836-battery" }, 279 { }, 280 }; 281 MODULE_DEVICE_TABLE(of, max17040_of_match); 282 283 static struct i2c_driver max17040_i2c_driver = { 284 .driver = { 285 .name = "max17040", 286 .of_match_table = max17040_of_match, 287 .pm = MAX17040_PM_OPS, 288 }, 289 .probe = max17040_probe, 290 .remove = max17040_remove, 291 .id_table = max17040_id, 292 }; 293 module_i2c_driver(max17040_i2c_driver); 294 295 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>"); 296 MODULE_DESCRIPTION("MAX17040 Fuel Gauge"); 297 MODULE_LICENSE("GPL"); 298