1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Battery driver for Acer Iconia Tab A500. 4 * 5 * Copyright 2020 GRATE-driver project. 6 * 7 * Based on downstream driver from Acer Inc. 8 * Based on NVIDIA Gas Gauge driver for SBS Compliant Batteries. 9 * 10 * Copyright (c) 2010, NVIDIA Corporation. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <linux/power_supply.h> 16 #include <linux/regmap.h> 17 #include <linux/sched.h> 18 #include <linux/slab.h> 19 #include <linux/workqueue.h> 20 #include <linux/property.h> 21 22 enum { 23 REG_CAPACITY, 24 REG_VOLTAGE, 25 REG_CURRENT, 26 REG_DESIGN_CAPACITY, 27 REG_TEMPERATURE, 28 }; 29 30 #define EC_DATA(_reg, _psp) { \ 31 .psp = POWER_SUPPLY_PROP_ ## _psp, \ 32 .reg = _reg, \ 33 } 34 35 static const struct battery_register { 36 enum power_supply_property psp; 37 unsigned int reg; 38 } ec_data[] = { 39 [REG_CAPACITY] = EC_DATA(0x00, CAPACITY), 40 [REG_VOLTAGE] = EC_DATA(0x01, VOLTAGE_NOW), 41 [REG_CURRENT] = EC_DATA(0x03, CURRENT_NOW), 42 [REG_DESIGN_CAPACITY] = EC_DATA(0x08, CHARGE_FULL_DESIGN), 43 [REG_TEMPERATURE] = EC_DATA(0x0a, TEMP), 44 }; 45 46 static const enum power_supply_property a500_battery_properties[] = { 47 POWER_SUPPLY_PROP_CAPACITY, 48 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 49 POWER_SUPPLY_PROP_CURRENT_NOW, 50 POWER_SUPPLY_PROP_PRESENT, 51 POWER_SUPPLY_PROP_STATUS, 52 POWER_SUPPLY_PROP_TECHNOLOGY, 53 POWER_SUPPLY_PROP_TEMP, 54 POWER_SUPPLY_PROP_VOLTAGE_NOW, 55 }; 56 57 struct a500_battery { 58 struct delayed_work poll_work; 59 struct power_supply *psy; 60 struct regmap *regmap; 61 unsigned int capacity; 62 }; 63 64 static bool a500_battery_update_capacity(struct a500_battery *bat) 65 { 66 unsigned int capacity; 67 int err; 68 69 err = regmap_read(bat->regmap, ec_data[REG_CAPACITY].reg, &capacity); 70 if (err) 71 return false; 72 73 /* capacity can be >100% even if max value is 100% */ 74 capacity = min(capacity, 100u); 75 76 if (bat->capacity != capacity) { 77 bat->capacity = capacity; 78 return true; 79 } 80 81 return false; 82 } 83 84 static int a500_battery_get_status(struct a500_battery *bat) 85 { 86 if (bat->capacity < 100) { 87 if (power_supply_am_i_supplied(bat->psy)) 88 return POWER_SUPPLY_STATUS_CHARGING; 89 else 90 return POWER_SUPPLY_STATUS_DISCHARGING; 91 } 92 93 return POWER_SUPPLY_STATUS_FULL; 94 } 95 96 static void a500_battery_unit_adjustment(struct device *dev, 97 enum power_supply_property psp, 98 union power_supply_propval *val) 99 { 100 const unsigned int base_unit_conversion = 1000; 101 const unsigned int temp_kelvin_to_celsius = 2731; 102 103 switch (psp) { 104 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 105 case POWER_SUPPLY_PROP_CURRENT_NOW: 106 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 107 val->intval *= base_unit_conversion; 108 break; 109 110 case POWER_SUPPLY_PROP_TEMP: 111 val->intval -= temp_kelvin_to_celsius; 112 break; 113 114 case POWER_SUPPLY_PROP_PRESENT: 115 val->intval = !!val->intval; 116 break; 117 118 default: 119 dev_dbg(dev, 120 "%s: no need for unit conversion %d\n", __func__, psp); 121 } 122 } 123 124 static int a500_battery_get_ec_data_index(struct device *dev, 125 enum power_supply_property psp) 126 { 127 unsigned int i; 128 129 /* 130 * DESIGN_CAPACITY register always returns a non-zero value if 131 * battery is connected and zero if disconnected, hence we'll use 132 * it for judging the battery presence. 133 */ 134 if (psp == POWER_SUPPLY_PROP_PRESENT) 135 psp = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; 136 137 for (i = 0; i < ARRAY_SIZE(ec_data); i++) 138 if (psp == ec_data[i].psp) 139 return i; 140 141 dev_dbg(dev, "%s: invalid property %u\n", __func__, psp); 142 143 return -EINVAL; 144 } 145 146 static int a500_battery_get_property(struct power_supply *psy, 147 enum power_supply_property psp, 148 union power_supply_propval *val) 149 { 150 struct a500_battery *bat = power_supply_get_drvdata(psy); 151 struct device *dev = psy->dev.parent; 152 int ret = 0; 153 154 switch (psp) { 155 case POWER_SUPPLY_PROP_STATUS: 156 val->intval = a500_battery_get_status(bat); 157 break; 158 159 case POWER_SUPPLY_PROP_TECHNOLOGY: 160 val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 161 break; 162 163 case POWER_SUPPLY_PROP_CAPACITY: 164 a500_battery_update_capacity(bat); 165 val->intval = bat->capacity; 166 break; 167 168 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 169 case POWER_SUPPLY_PROP_CURRENT_NOW: 170 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 171 case POWER_SUPPLY_PROP_PRESENT: 172 case POWER_SUPPLY_PROP_TEMP: 173 ret = a500_battery_get_ec_data_index(dev, psp); 174 if (ret < 0) 175 break; 176 177 ret = regmap_read(bat->regmap, ec_data[ret].reg, &val->intval); 178 break; 179 180 default: 181 dev_err(dev, "%s: invalid property %u\n", __func__, psp); 182 return -EINVAL; 183 } 184 185 if (!ret) { 186 /* convert units to match requirements of power supply class */ 187 a500_battery_unit_adjustment(dev, psp, val); 188 } 189 190 dev_dbg(dev, "%s: property = %d, value = %x\n", 191 __func__, psp, val->intval); 192 193 /* return NODATA for properties if battery not presents */ 194 if (ret) 195 return -ENODATA; 196 197 return 0; 198 } 199 200 static void a500_battery_poll_work(struct work_struct *work) 201 { 202 struct a500_battery *bat; 203 bool capacity_changed; 204 205 bat = container_of(work, struct a500_battery, poll_work.work); 206 capacity_changed = a500_battery_update_capacity(bat); 207 208 if (capacity_changed) 209 power_supply_changed(bat->psy); 210 211 /* continuously send uevent notification */ 212 schedule_delayed_work(&bat->poll_work, 30 * HZ); 213 } 214 215 static const struct power_supply_desc a500_battery_desc = { 216 .name = "ec-battery", 217 .type = POWER_SUPPLY_TYPE_BATTERY, 218 .properties = a500_battery_properties, 219 .get_property = a500_battery_get_property, 220 .num_properties = ARRAY_SIZE(a500_battery_properties), 221 .external_power_changed = power_supply_changed, 222 }; 223 224 static int a500_battery_probe(struct platform_device *pdev) 225 { 226 struct power_supply_config psy_cfg = {}; 227 struct a500_battery *bat; 228 229 bat = devm_kzalloc(&pdev->dev, sizeof(*bat), GFP_KERNEL); 230 if (!bat) 231 return -ENOMEM; 232 233 platform_set_drvdata(pdev, bat); 234 235 psy_cfg.fwnode = dev_fwnode(pdev->dev.parent); 236 psy_cfg.drv_data = bat; 237 psy_cfg.no_wakeup_source = true; 238 239 bat->regmap = dev_get_regmap(pdev->dev.parent, "KB930"); 240 if (!bat->regmap) 241 return -EINVAL; 242 243 bat->psy = devm_power_supply_register(&pdev->dev, 244 &a500_battery_desc, 245 &psy_cfg); 246 if (IS_ERR(bat->psy)) 247 return dev_err_probe(&pdev->dev, PTR_ERR(bat->psy), 248 "failed to register battery\n"); 249 250 INIT_DELAYED_WORK(&bat->poll_work, a500_battery_poll_work); 251 schedule_delayed_work(&bat->poll_work, HZ); 252 253 return 0; 254 } 255 256 static void a500_battery_remove(struct platform_device *pdev) 257 { 258 struct a500_battery *bat = dev_get_drvdata(&pdev->dev); 259 260 cancel_delayed_work_sync(&bat->poll_work); 261 } 262 263 static int __maybe_unused a500_battery_suspend(struct device *dev) 264 { 265 struct a500_battery *bat = dev_get_drvdata(dev); 266 267 cancel_delayed_work_sync(&bat->poll_work); 268 269 return 0; 270 } 271 272 static int __maybe_unused a500_battery_resume(struct device *dev) 273 { 274 struct a500_battery *bat = dev_get_drvdata(dev); 275 276 schedule_delayed_work(&bat->poll_work, HZ); 277 278 return 0; 279 } 280 281 static SIMPLE_DEV_PM_OPS(a500_battery_pm_ops, 282 a500_battery_suspend, a500_battery_resume); 283 284 static struct platform_driver a500_battery_driver = { 285 .driver = { 286 .name = "acer-a500-iconia-battery", 287 .pm = &a500_battery_pm_ops, 288 }, 289 .probe = a500_battery_probe, 290 .remove = a500_battery_remove, 291 }; 292 module_platform_driver(a500_battery_driver); 293 294 MODULE_DESCRIPTION("Battery gauge driver for Acer Iconia Tab A500"); 295 MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); 296 MODULE_ALIAS("platform:acer-a500-iconia-battery"); 297 MODULE_LICENSE("GPL"); 298