1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Power supply driver for the RICOH RN5T618 power management chip family 4 * 5 * Copyright (C) 2020 Andreas Kemnade 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/device.h> 10 #include <linux/bitops.h> 11 #include <linux/errno.h> 12 #include <linux/init.h> 13 #include <linux/interrupt.h> 14 #include <linux/module.h> 15 #include <linux/mfd/rn5t618.h> 16 #include <linux/platform_device.h> 17 #include <linux/power_supply.h> 18 #include <linux/regmap.h> 19 #include <linux/slab.h> 20 21 #define CHG_STATE_ADP_INPUT 0x40 22 #define CHG_STATE_USB_INPUT 0x80 23 #define CHG_STATE_MASK 0x1f 24 #define CHG_STATE_CHG_OFF 0 25 #define CHG_STATE_CHG_READY_VADP 1 26 #define CHG_STATE_CHG_TRICKLE 2 27 #define CHG_STATE_CHG_RAPID 3 28 #define CHG_STATE_CHG_COMPLETE 4 29 #define CHG_STATE_SUSPEND 5 30 #define CHG_STATE_VCHG_OVER_VOL 6 31 #define CHG_STATE_BAT_ERROR 7 32 #define CHG_STATE_NO_BAT 8 33 #define CHG_STATE_BAT_OVER_VOL 9 34 #define CHG_STATE_BAT_TEMP_ERR 10 35 #define CHG_STATE_DIE_ERR 11 36 #define CHG_STATE_DIE_SHUTDOWN 12 37 #define CHG_STATE_NO_BAT2 13 38 #define CHG_STATE_CHG_READY_VUSB 14 39 40 #define FG_ENABLE 1 41 42 struct rn5t618_power_info { 43 struct rn5t618 *rn5t618; 44 struct platform_device *pdev; 45 struct power_supply *battery; 46 struct power_supply *usb; 47 struct power_supply *adp; 48 int irq; 49 }; 50 51 static enum power_supply_property rn5t618_usb_props[] = { 52 POWER_SUPPLY_PROP_STATUS, 53 POWER_SUPPLY_PROP_ONLINE, 54 }; 55 56 static enum power_supply_property rn5t618_adp_props[] = { 57 POWER_SUPPLY_PROP_STATUS, 58 POWER_SUPPLY_PROP_ONLINE, 59 }; 60 61 62 static enum power_supply_property rn5t618_battery_props[] = { 63 POWER_SUPPLY_PROP_STATUS, 64 POWER_SUPPLY_PROP_PRESENT, 65 POWER_SUPPLY_PROP_VOLTAGE_NOW, 66 POWER_SUPPLY_PROP_CURRENT_NOW, 67 POWER_SUPPLY_PROP_CAPACITY, 68 POWER_SUPPLY_PROP_TEMP, 69 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 70 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 71 POWER_SUPPLY_PROP_TECHNOLOGY, 72 POWER_SUPPLY_PROP_CHARGE_FULL, 73 POWER_SUPPLY_PROP_CHARGE_NOW, 74 }; 75 76 static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info, 77 u8 reg, u16 *result) 78 { 79 int ret, i; 80 u8 data[2]; 81 u16 old, new; 82 83 old = 0; 84 /* Prevent races when registers are changing. */ 85 for (i = 0; i < 3; i++) { 86 ret = regmap_bulk_read(info->rn5t618->regmap, 87 reg, data, sizeof(data)); 88 if (ret) 89 return ret; 90 91 new = data[0] << 8; 92 new |= data[1]; 93 if (new == old) 94 break; 95 96 old = new; 97 } 98 99 *result = new; 100 101 return 0; 102 } 103 104 static int rn5t618_decode_status(unsigned int status) 105 { 106 switch (status & CHG_STATE_MASK) { 107 case CHG_STATE_CHG_OFF: 108 case CHG_STATE_SUSPEND: 109 case CHG_STATE_VCHG_OVER_VOL: 110 case CHG_STATE_DIE_SHUTDOWN: 111 return POWER_SUPPLY_STATUS_DISCHARGING; 112 113 case CHG_STATE_CHG_TRICKLE: 114 case CHG_STATE_CHG_RAPID: 115 return POWER_SUPPLY_STATUS_CHARGING; 116 117 case CHG_STATE_CHG_COMPLETE: 118 return POWER_SUPPLY_STATUS_FULL; 119 120 default: 121 return POWER_SUPPLY_STATUS_NOT_CHARGING; 122 } 123 } 124 125 static int rn5t618_battery_status(struct rn5t618_power_info *info, 126 union power_supply_propval *val) 127 { 128 unsigned int v; 129 int ret; 130 131 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v); 132 if (ret) 133 return ret; 134 135 val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 136 137 if (v & 0xc0) { /* USB or ADP plugged */ 138 val->intval = rn5t618_decode_status(v); 139 } else 140 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 141 142 return ret; 143 } 144 145 static int rn5t618_battery_present(struct rn5t618_power_info *info, 146 union power_supply_propval *val) 147 { 148 unsigned int v; 149 int ret; 150 151 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v); 152 if (ret) 153 return ret; 154 155 v &= CHG_STATE_MASK; 156 if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2)) 157 val->intval = 0; 158 else 159 val->intval = 1; 160 161 return ret; 162 } 163 164 static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info, 165 union power_supply_propval *val) 166 { 167 u16 res; 168 int ret; 169 170 ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res); 171 if (ret) 172 return ret; 173 174 val->intval = res * 2 * 2500 / 4095 * 1000; 175 176 return 0; 177 } 178 179 static int rn5t618_battery_current_now(struct rn5t618_power_info *info, 180 union power_supply_propval *val) 181 { 182 u16 res; 183 int ret; 184 185 ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res); 186 if (ret) 187 return ret; 188 189 /* current is negative when discharging */ 190 val->intval = sign_extend32(res, 13) * 1000; 191 192 return 0; 193 } 194 195 static int rn5t618_battery_capacity(struct rn5t618_power_info *info, 196 union power_supply_propval *val) 197 { 198 unsigned int v; 199 int ret; 200 201 ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v); 202 if (ret) 203 return ret; 204 205 val->intval = v; 206 207 return 0; 208 } 209 210 static int rn5t618_battery_temp(struct rn5t618_power_info *info, 211 union power_supply_propval *val) 212 { 213 u16 res; 214 int ret; 215 216 ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res); 217 if (ret) 218 return ret; 219 220 val->intval = sign_extend32(res, 11) * 10 / 16; 221 222 return 0; 223 } 224 225 static int rn5t618_battery_tte(struct rn5t618_power_info *info, 226 union power_supply_propval *val) 227 { 228 u16 res; 229 int ret; 230 231 ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res); 232 if (ret) 233 return ret; 234 235 if (res == 65535) 236 return -ENODATA; 237 238 val->intval = res * 60; 239 240 return 0; 241 } 242 243 static int rn5t618_battery_ttf(struct rn5t618_power_info *info, 244 union power_supply_propval *val) 245 { 246 u16 res; 247 int ret; 248 249 ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res); 250 if (ret) 251 return ret; 252 253 if (res == 65535) 254 return -ENODATA; 255 256 val->intval = res * 60; 257 258 return 0; 259 } 260 261 static int rn5t618_battery_charge_full(struct rn5t618_power_info *info, 262 union power_supply_propval *val) 263 { 264 u16 res; 265 int ret; 266 267 ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res); 268 if (ret) 269 return ret; 270 271 val->intval = res * 1000; 272 273 return 0; 274 } 275 276 static int rn5t618_battery_charge_now(struct rn5t618_power_info *info, 277 union power_supply_propval *val) 278 { 279 u16 res; 280 int ret; 281 282 ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res); 283 if (ret) 284 return ret; 285 286 val->intval = res * 1000; 287 288 return 0; 289 } 290 291 static int rn5t618_battery_get_property(struct power_supply *psy, 292 enum power_supply_property psp, 293 union power_supply_propval *val) 294 { 295 int ret = 0; 296 struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 297 298 switch (psp) { 299 case POWER_SUPPLY_PROP_STATUS: 300 ret = rn5t618_battery_status(info, val); 301 break; 302 case POWER_SUPPLY_PROP_PRESENT: 303 ret = rn5t618_battery_present(info, val); 304 break; 305 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 306 ret = rn5t618_battery_voltage_now(info, val); 307 break; 308 case POWER_SUPPLY_PROP_CURRENT_NOW: 309 ret = rn5t618_battery_current_now(info, val); 310 break; 311 case POWER_SUPPLY_PROP_CAPACITY: 312 ret = rn5t618_battery_capacity(info, val); 313 break; 314 case POWER_SUPPLY_PROP_TEMP: 315 ret = rn5t618_battery_temp(info, val); 316 break; 317 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 318 ret = rn5t618_battery_tte(info, val); 319 break; 320 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 321 ret = rn5t618_battery_ttf(info, val); 322 break; 323 case POWER_SUPPLY_PROP_TECHNOLOGY: 324 val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 325 break; 326 case POWER_SUPPLY_PROP_CHARGE_FULL: 327 ret = rn5t618_battery_charge_full(info, val); 328 break; 329 case POWER_SUPPLY_PROP_CHARGE_NOW: 330 ret = rn5t618_battery_charge_now(info, val); 331 break; 332 default: 333 return -EINVAL; 334 } 335 336 return ret; 337 } 338 339 static int rn5t618_adp_get_property(struct power_supply *psy, 340 enum power_supply_property psp, 341 union power_supply_propval *val) 342 { 343 struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 344 unsigned int chgstate; 345 bool online; 346 int ret; 347 348 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate); 349 if (ret) 350 return ret; 351 352 online = !!(chgstate & CHG_STATE_ADP_INPUT); 353 354 switch (psp) { 355 case POWER_SUPPLY_PROP_ONLINE: 356 val->intval = online; 357 break; 358 case POWER_SUPPLY_PROP_STATUS: 359 if (!online) { 360 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 361 break; 362 } 363 val->intval = rn5t618_decode_status(chgstate); 364 if (val->intval != POWER_SUPPLY_STATUS_CHARGING) 365 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 366 367 break; 368 default: 369 return -EINVAL; 370 } 371 372 return 0; 373 } 374 375 static int rn5t618_usb_get_property(struct power_supply *psy, 376 enum power_supply_property psp, 377 union power_supply_propval *val) 378 { 379 struct rn5t618_power_info *info = power_supply_get_drvdata(psy); 380 unsigned int chgstate; 381 bool online; 382 int ret; 383 384 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate); 385 if (ret) 386 return ret; 387 388 online = !!(chgstate & CHG_STATE_USB_INPUT); 389 390 switch (psp) { 391 case POWER_SUPPLY_PROP_ONLINE: 392 val->intval = online; 393 break; 394 case POWER_SUPPLY_PROP_STATUS: 395 if (!online) { 396 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 397 break; 398 } 399 val->intval = rn5t618_decode_status(chgstate); 400 if (val->intval != POWER_SUPPLY_STATUS_CHARGING) 401 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 402 403 break; 404 default: 405 return -EINVAL; 406 } 407 408 return 0; 409 } 410 411 static const struct power_supply_desc rn5t618_battery_desc = { 412 .name = "rn5t618-battery", 413 .type = POWER_SUPPLY_TYPE_BATTERY, 414 .properties = rn5t618_battery_props, 415 .num_properties = ARRAY_SIZE(rn5t618_battery_props), 416 .get_property = rn5t618_battery_get_property, 417 }; 418 419 static const struct power_supply_desc rn5t618_adp_desc = { 420 .name = "rn5t618-adp", 421 .type = POWER_SUPPLY_TYPE_MAINS, 422 .properties = rn5t618_adp_props, 423 .num_properties = ARRAY_SIZE(rn5t618_adp_props), 424 .get_property = rn5t618_adp_get_property, 425 }; 426 427 static const struct power_supply_desc rn5t618_usb_desc = { 428 .name = "rn5t618-usb", 429 .type = POWER_SUPPLY_TYPE_USB, 430 .properties = rn5t618_usb_props, 431 .num_properties = ARRAY_SIZE(rn5t618_usb_props), 432 .get_property = rn5t618_usb_get_property, 433 }; 434 435 static irqreturn_t rn5t618_charger_irq(int irq, void *data) 436 { 437 struct device *dev = data; 438 struct rn5t618_power_info *info = dev_get_drvdata(dev); 439 440 unsigned int ctrl, stat1, stat2, err; 441 442 regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err); 443 regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl); 444 regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1); 445 regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2); 446 447 regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0); 448 regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0); 449 regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0); 450 regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0); 451 452 dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n", 453 err, ctrl, stat1, stat2); 454 455 power_supply_changed(info->usb); 456 power_supply_changed(info->adp); 457 power_supply_changed(info->battery); 458 459 return IRQ_HANDLED; 460 } 461 462 static int rn5t618_power_probe(struct platform_device *pdev) 463 { 464 int ret = 0; 465 unsigned int v; 466 struct power_supply_config psy_cfg = {}; 467 struct rn5t618_power_info *info; 468 469 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 470 if (!info) 471 return -ENOMEM; 472 473 info->pdev = pdev; 474 info->rn5t618 = dev_get_drvdata(pdev->dev.parent); 475 info->irq = -1; 476 477 platform_set_drvdata(pdev, info); 478 479 ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v); 480 if (ret) 481 return ret; 482 483 if (!(v & FG_ENABLE)) { 484 /* E.g. the vendor kernels of various Kobo and Tolino Ebook 485 * readers disable the fuel gauge on shutdown. If a kernel 486 * without fuel gauge support is booted after that, the fuel 487 * gauge will get decalibrated. 488 */ 489 dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n"); 490 dev_info(&pdev->dev, "Expect imprecise results\n"); 491 regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL, 492 FG_ENABLE, FG_ENABLE); 493 } 494 495 psy_cfg.drv_data = info; 496 info->battery = devm_power_supply_register(&pdev->dev, 497 &rn5t618_battery_desc, 498 &psy_cfg); 499 if (IS_ERR(info->battery)) { 500 ret = PTR_ERR(info->battery); 501 dev_err(&pdev->dev, "failed to register battery: %d\n", ret); 502 return ret; 503 } 504 505 info->adp = devm_power_supply_register(&pdev->dev, 506 &rn5t618_adp_desc, 507 &psy_cfg); 508 if (IS_ERR(info->adp)) { 509 ret = PTR_ERR(info->adp); 510 dev_err(&pdev->dev, "failed to register adp: %d\n", ret); 511 return ret; 512 } 513 514 info->usb = devm_power_supply_register(&pdev->dev, 515 &rn5t618_usb_desc, 516 &psy_cfg); 517 if (IS_ERR(info->usb)) { 518 ret = PTR_ERR(info->usb); 519 dev_err(&pdev->dev, "failed to register usb: %d\n", ret); 520 return ret; 521 } 522 523 if (info->rn5t618->irq_data) 524 info->irq = regmap_irq_get_virq(info->rn5t618->irq_data, 525 RN5T618_IRQ_CHG); 526 527 if (info->irq < 0) 528 info->irq = -1; 529 else { 530 ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, 531 rn5t618_charger_irq, 532 IRQF_ONESHOT, 533 "rn5t618_power", 534 &pdev->dev); 535 536 if (ret < 0) { 537 dev_err(&pdev->dev, "request IRQ:%d fail\n", 538 info->irq); 539 info->irq = -1; 540 } 541 } 542 543 return 0; 544 } 545 546 static struct platform_driver rn5t618_power_driver = { 547 .driver = { 548 .name = "rn5t618-power", 549 }, 550 .probe = rn5t618_power_probe, 551 }; 552 553 module_platform_driver(rn5t618_power_driver); 554 MODULE_ALIAS("platform:rn5t618-power"); 555 MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618"); 556 MODULE_LICENSE("GPL"); 557