824 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Power supply driver for the RICOH RN5T618 power management chip family4 *5 * Copyright (C) 2020 Andreas Kemnade6 */7 8#include <linux/kernel.h>9#include <linux/device.h>10#include <linux/bitops.h>11#include <linux/errno.h>12#include <linux/iio/consumer.h>13#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/module.h>16#include <linux/mfd/rn5t618.h>17#include <linux/platform_device.h>18#include <linux/power_supply.h>19#include <linux/regmap.h>20#include <linux/slab.h>21 22#define CHG_STATE_ADP_INPUT 0x4023#define CHG_STATE_USB_INPUT 0x8024#define CHG_STATE_MASK 0x1f25#define CHG_STATE_CHG_OFF 026#define CHG_STATE_CHG_READY_VADP 127#define CHG_STATE_CHG_TRICKLE 228#define CHG_STATE_CHG_RAPID 329#define CHG_STATE_CHG_COMPLETE 430#define CHG_STATE_SUSPEND 531#define CHG_STATE_VCHG_OVER_VOL 632#define CHG_STATE_BAT_ERROR 733#define CHG_STATE_NO_BAT 834#define CHG_STATE_BAT_OVER_VOL 935#define CHG_STATE_BAT_TEMP_ERR 1036#define CHG_STATE_DIE_ERR 1137#define CHG_STATE_DIE_SHUTDOWN 1238#define CHG_STATE_NO_BAT2 1339#define CHG_STATE_CHG_READY_VUSB 1440 41#define GCHGDET_TYPE_MASK 0x3042#define GCHGDET_TYPE_SDP 0x0043#define GCHGDET_TYPE_CDP 0x1044#define GCHGDET_TYPE_DCP 0x2045 46#define FG_ENABLE 147 48/*49 * Formula seems accurate for battery current, but for USB current around 70mA50 * per step was seen on Kobo Clara HD but all sources show the same formula51 * also fur USB current. To avoid accidentially unwanted high currents we stick52 * to that formula53 */54#define TO_CUR_REG(x) ((x) / 100000 - 1)55#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)56#define CHG_MIN_CUR 10000057#define CHG_MAX_CUR 180000058#define ADP_MAX_CUR 250000059#define USB_MAX_CUR 140000060 61 62struct rn5t618_power_info {63 struct rn5t618 *rn5t618;64 struct platform_device *pdev;65 struct power_supply *battery;66 struct power_supply *usb;67 struct power_supply *adp;68 struct iio_channel *channel_vusb;69 struct iio_channel *channel_vadp;70 int irq;71};72 73static enum power_supply_property rn5t618_usb_props[] = {74 /* input current limit is not very accurate */75 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,76 POWER_SUPPLY_PROP_VOLTAGE_NOW,77 POWER_SUPPLY_PROP_STATUS,78 POWER_SUPPLY_PROP_USB_TYPE,79 POWER_SUPPLY_PROP_ONLINE,80};81 82static enum power_supply_property rn5t618_adp_props[] = {83 /* input current limit is not very accurate */84 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,85 POWER_SUPPLY_PROP_VOLTAGE_NOW,86 POWER_SUPPLY_PROP_STATUS,87 POWER_SUPPLY_PROP_ONLINE,88};89 90 91static enum power_supply_property rn5t618_battery_props[] = {92 POWER_SUPPLY_PROP_STATUS,93 POWER_SUPPLY_PROP_PRESENT,94 POWER_SUPPLY_PROP_VOLTAGE_NOW,95 POWER_SUPPLY_PROP_CURRENT_NOW,96 POWER_SUPPLY_PROP_CAPACITY,97 POWER_SUPPLY_PROP_TEMP,98 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,99 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,100 POWER_SUPPLY_PROP_TECHNOLOGY,101 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,102 POWER_SUPPLY_PROP_CHARGE_FULL,103 POWER_SUPPLY_PROP_CHARGE_NOW,104};105 106static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info,107 u8 reg, u16 *result)108{109 int ret, i;110 u8 data[2];111 u16 old, new;112 113 old = 0;114 /* Prevent races when registers are changing. */115 for (i = 0; i < 3; i++) {116 ret = regmap_bulk_read(info->rn5t618->regmap,117 reg, data, sizeof(data));118 if (ret)119 return ret;120 121 new = data[0] << 8;122 new |= data[1];123 if (new == old)124 break;125 126 old = new;127 }128 129 *result = new;130 131 return 0;132}133 134static int rn5t618_decode_status(unsigned int status)135{136 switch (status & CHG_STATE_MASK) {137 case CHG_STATE_CHG_OFF:138 case CHG_STATE_SUSPEND:139 case CHG_STATE_VCHG_OVER_VOL:140 case CHG_STATE_DIE_SHUTDOWN:141 return POWER_SUPPLY_STATUS_DISCHARGING;142 143 case CHG_STATE_CHG_TRICKLE:144 case CHG_STATE_CHG_RAPID:145 return POWER_SUPPLY_STATUS_CHARGING;146 147 case CHG_STATE_CHG_COMPLETE:148 return POWER_SUPPLY_STATUS_FULL;149 150 default:151 return POWER_SUPPLY_STATUS_NOT_CHARGING;152 }153}154 155static int rn5t618_battery_status(struct rn5t618_power_info *info,156 union power_supply_propval *val)157{158 unsigned int v;159 int ret;160 161 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);162 if (ret)163 return ret;164 165 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;166 167 if (v & 0xc0) { /* USB or ADP plugged */168 val->intval = rn5t618_decode_status(v);169 } else170 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;171 172 return ret;173}174 175static int rn5t618_battery_present(struct rn5t618_power_info *info,176 union power_supply_propval *val)177{178 unsigned int v;179 int ret;180 181 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);182 if (ret)183 return ret;184 185 v &= CHG_STATE_MASK;186 if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2))187 val->intval = 0;188 else189 val->intval = 1;190 191 return ret;192}193 194static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info,195 union power_supply_propval *val)196{197 u16 res;198 int ret;199 200 ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res);201 if (ret)202 return ret;203 204 val->intval = res * 2 * 2500 / 4095 * 1000;205 206 return 0;207}208 209static int rn5t618_battery_current_now(struct rn5t618_power_info *info,210 union power_supply_propval *val)211{212 u16 res;213 int ret;214 215 ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res);216 if (ret)217 return ret;218 219 /* current is negative when discharging */220 val->intval = sign_extend32(res, 13) * 1000;221 222 return 0;223}224 225static int rn5t618_battery_capacity(struct rn5t618_power_info *info,226 union power_supply_propval *val)227{228 unsigned int v;229 int ret;230 231 ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v);232 if (ret)233 return ret;234 235 val->intval = v;236 237 return 0;238}239 240static int rn5t618_battery_temp(struct rn5t618_power_info *info,241 union power_supply_propval *val)242{243 u16 res;244 int ret;245 246 ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res);247 if (ret)248 return ret;249 250 val->intval = sign_extend32(res, 11) * 10 / 16;251 252 return 0;253}254 255static int rn5t618_battery_tte(struct rn5t618_power_info *info,256 union power_supply_propval *val)257{258 u16 res;259 int ret;260 261 ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);262 if (ret)263 return ret;264 265 if (res == 65535)266 return -ENODATA;267 268 val->intval = res * 60;269 270 return 0;271}272 273static int rn5t618_battery_ttf(struct rn5t618_power_info *info,274 union power_supply_propval *val)275{276 u16 res;277 int ret;278 279 ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res);280 if (ret)281 return ret;282 283 if (res == 65535)284 return -ENODATA;285 286 val->intval = res * 60;287 288 return 0;289}290 291static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,292 const union power_supply_propval *val)293{294 if (val->intval < CHG_MIN_CUR)295 return -EINVAL;296 297 if (val->intval >= CHG_MAX_CUR)298 return -EINVAL;299 300 return regmap_update_bits(info->rn5t618->regmap,301 RN5T618_CHGISET,302 0x1F, TO_CUR_REG(val->intval));303}304 305static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,306 union power_supply_propval *val)307{308 unsigned int regval;309 int ret;310 311 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,312 ®val);313 if (ret < 0)314 return ret;315 316 val->intval = FROM_CUR_REG(regval);317 318 return 0;319}320 321static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,322 union power_supply_propval *val)323{324 u16 res;325 int ret;326 327 ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res);328 if (ret)329 return ret;330 331 val->intval = res * 1000;332 333 return 0;334}335 336static int rn5t618_battery_charge_now(struct rn5t618_power_info *info,337 union power_supply_propval *val)338{339 u16 res;340 int ret;341 342 ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res);343 if (ret)344 return ret;345 346 val->intval = res * 1000;347 348 return 0;349}350 351static int rn5t618_battery_get_property(struct power_supply *psy,352 enum power_supply_property psp,353 union power_supply_propval *val)354{355 int ret = 0;356 struct rn5t618_power_info *info = power_supply_get_drvdata(psy);357 358 switch (psp) {359 case POWER_SUPPLY_PROP_STATUS:360 ret = rn5t618_battery_status(info, val);361 break;362 case POWER_SUPPLY_PROP_PRESENT:363 ret = rn5t618_battery_present(info, val);364 break;365 case POWER_SUPPLY_PROP_VOLTAGE_NOW:366 ret = rn5t618_battery_voltage_now(info, val);367 break;368 case POWER_SUPPLY_PROP_CURRENT_NOW:369 ret = rn5t618_battery_current_now(info, val);370 break;371 case POWER_SUPPLY_PROP_CAPACITY:372 ret = rn5t618_battery_capacity(info, val);373 break;374 case POWER_SUPPLY_PROP_TEMP:375 ret = rn5t618_battery_temp(info, val);376 break;377 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:378 ret = rn5t618_battery_tte(info, val);379 break;380 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:381 ret = rn5t618_battery_ttf(info, val);382 break;383 case POWER_SUPPLY_PROP_TECHNOLOGY:384 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;385 break;386 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:387 ret = rn5t618_battery_get_current_limit(info, val);388 break;389 case POWER_SUPPLY_PROP_CHARGE_FULL:390 ret = rn5t618_battery_charge_full(info, val);391 break;392 case POWER_SUPPLY_PROP_CHARGE_NOW:393 ret = rn5t618_battery_charge_now(info, val);394 break;395 default:396 return -EINVAL;397 }398 399 return ret;400}401 402static int rn5t618_battery_set_property(struct power_supply *psy,403 enum power_supply_property psp,404 const union power_supply_propval *val)405{406 struct rn5t618_power_info *info = power_supply_get_drvdata(psy);407 408 switch (psp) {409 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:410 return rn5t618_battery_set_current_limit(info, val);411 default:412 return -EINVAL;413 }414}415 416static int rn5t618_battery_property_is_writeable(struct power_supply *psy,417 enum power_supply_property psp)418{419 switch (psp) {420 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:421 return true;422 default:423 return false;424 }425}426 427static int rn5t618_adp_get_property(struct power_supply *psy,428 enum power_supply_property psp,429 union power_supply_propval *val)430{431 struct rn5t618_power_info *info = power_supply_get_drvdata(psy);432 unsigned int chgstate;433 unsigned int regval;434 bool online;435 int ret;436 437 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);438 if (ret)439 return ret;440 441 online = !!(chgstate & CHG_STATE_ADP_INPUT);442 443 switch (psp) {444 case POWER_SUPPLY_PROP_ONLINE:445 val->intval = online;446 break;447 case POWER_SUPPLY_PROP_STATUS:448 if (!online) {449 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;450 break;451 }452 val->intval = rn5t618_decode_status(chgstate);453 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)454 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;455 456 break;457 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:458 ret = regmap_read(info->rn5t618->regmap,459 RN5T618_REGISET1, ®val);460 if (ret < 0)461 return ret;462 463 val->intval = FROM_CUR_REG(regval);464 break;465 case POWER_SUPPLY_PROP_VOLTAGE_NOW:466 if (!info->channel_vadp)467 return -ENODATA;468 469 ret = iio_read_channel_processed_scale(info->channel_vadp, &val->intval, 1000);470 if (ret < 0)471 return ret;472 473 break;474 default:475 return -EINVAL;476 }477 478 return 0;479}480 481static int rn5t618_adp_set_property(struct power_supply *psy,482 enum power_supply_property psp,483 const union power_supply_propval *val)484{485 struct rn5t618_power_info *info = power_supply_get_drvdata(psy);486 int ret;487 488 switch (psp) {489 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:490 if (val->intval > ADP_MAX_CUR)491 return -EINVAL;492 493 if (val->intval < CHG_MIN_CUR)494 return -EINVAL;495 496 ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,497 TO_CUR_REG(val->intval));498 if (ret < 0)499 return ret;500 501 break;502 default:503 return -EINVAL;504 }505 506 return 0;507}508 509static int rn5t618_adp_property_is_writeable(struct power_supply *psy,510 enum power_supply_property psp)511{512 switch (psp) {513 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:514 return true;515 default:516 return false;517 }518}519 520static int rc5t619_usb_get_type(struct rn5t618_power_info *info,521 union power_supply_propval *val)522{523 unsigned int regval;524 int ret;525 526 ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, ®val);527 if (ret < 0)528 return ret;529 530 switch (regval & GCHGDET_TYPE_MASK) {531 case GCHGDET_TYPE_SDP:532 val->intval = POWER_SUPPLY_USB_TYPE_SDP;533 break;534 case GCHGDET_TYPE_CDP:535 val->intval = POWER_SUPPLY_USB_TYPE_CDP;536 break;537 case GCHGDET_TYPE_DCP:538 val->intval = POWER_SUPPLY_USB_TYPE_DCP;539 break;540 default:541 val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;542 }543 544 return 0;545}546 547static int rn5t618_usb_get_property(struct power_supply *psy,548 enum power_supply_property psp,549 union power_supply_propval *val)550{551 struct rn5t618_power_info *info = power_supply_get_drvdata(psy);552 unsigned int chgstate;553 unsigned int regval;554 bool online;555 int ret;556 557 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);558 if (ret)559 return ret;560 561 online = !!(chgstate & CHG_STATE_USB_INPUT);562 563 switch (psp) {564 case POWER_SUPPLY_PROP_ONLINE:565 val->intval = online;566 break;567 case POWER_SUPPLY_PROP_STATUS:568 if (!online) {569 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;570 break;571 }572 val->intval = rn5t618_decode_status(chgstate);573 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)574 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;575 576 break;577 case POWER_SUPPLY_PROP_USB_TYPE:578 if (!online || (info->rn5t618->variant != RC5T619))579 return -ENODATA;580 581 return rc5t619_usb_get_type(info, val);582 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:583 ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,584 ®val);585 if (ret < 0)586 return ret;587 588 val->intval = 0;589 if (regval & 2) {590 ret = regmap_read(info->rn5t618->regmap,591 RN5T618_REGISET2,592 ®val);593 if (ret < 0)594 return ret;595 596 val->intval = FROM_CUR_REG(regval);597 }598 break;599 case POWER_SUPPLY_PROP_VOLTAGE_NOW:600 if (!info->channel_vusb)601 return -ENODATA;602 603 ret = iio_read_channel_processed_scale(info->channel_vusb, &val->intval, 1000);604 if (ret < 0)605 return ret;606 607 break;608 default:609 return -EINVAL;610 }611 612 return 0;613}614 615static int rn5t618_usb_set_property(struct power_supply *psy,616 enum power_supply_property psp,617 const union power_supply_propval *val)618{619 struct rn5t618_power_info *info = power_supply_get_drvdata(psy);620 int ret;621 622 switch (psp) {623 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:624 if (val->intval > USB_MAX_CUR)625 return -EINVAL;626 627 if (val->intval < CHG_MIN_CUR)628 return -EINVAL;629 630 ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,631 0xE0 | TO_CUR_REG(val->intval));632 if (ret < 0)633 return ret;634 635 break;636 default:637 return -EINVAL;638 }639 640 return 0;641}642 643static int rn5t618_usb_property_is_writeable(struct power_supply *psy,644 enum power_supply_property psp)645{646 switch (psp) {647 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:648 return true;649 default:650 return false;651 }652}653 654static const struct power_supply_desc rn5t618_battery_desc = {655 .name = "rn5t618-battery",656 .type = POWER_SUPPLY_TYPE_BATTERY,657 .properties = rn5t618_battery_props,658 .num_properties = ARRAY_SIZE(rn5t618_battery_props),659 .get_property = rn5t618_battery_get_property,660 .set_property = rn5t618_battery_set_property,661 .property_is_writeable = rn5t618_battery_property_is_writeable,662};663 664static const struct power_supply_desc rn5t618_adp_desc = {665 .name = "rn5t618-adp",666 .type = POWER_SUPPLY_TYPE_MAINS,667 .properties = rn5t618_adp_props,668 .num_properties = ARRAY_SIZE(rn5t618_adp_props),669 .get_property = rn5t618_adp_get_property,670 .set_property = rn5t618_adp_set_property,671 .property_is_writeable = rn5t618_adp_property_is_writeable,672};673 674static const struct power_supply_desc rn5t618_usb_desc = {675 .name = "rn5t618-usb",676 .type = POWER_SUPPLY_TYPE_USB,677 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |678 BIT(POWER_SUPPLY_USB_TYPE_CDP) |679 BIT(POWER_SUPPLY_USB_TYPE_DCP) |680 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),681 .properties = rn5t618_usb_props,682 .num_properties = ARRAY_SIZE(rn5t618_usb_props),683 .get_property = rn5t618_usb_get_property,684 .set_property = rn5t618_usb_set_property,685 .property_is_writeable = rn5t618_usb_property_is_writeable,686};687 688static irqreturn_t rn5t618_charger_irq(int irq, void *data)689{690 struct device *dev = data;691 struct rn5t618_power_info *info = dev_get_drvdata(dev);692 693 unsigned int ctrl, stat1, stat2, err;694 695 regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err);696 regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl);697 regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1);698 regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2);699 700 regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0);701 regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0);702 regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0);703 regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0);704 705 dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n",706 err, ctrl, stat1, stat2);707 708 power_supply_changed(info->usb);709 power_supply_changed(info->adp);710 power_supply_changed(info->battery);711 712 return IRQ_HANDLED;713}714 715static int rn5t618_power_probe(struct platform_device *pdev)716{717 int ret = 0;718 unsigned int v;719 struct power_supply_config psy_cfg = {};720 struct rn5t618_power_info *info;721 722 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);723 if (!info)724 return -ENOMEM;725 726 info->pdev = pdev;727 info->rn5t618 = dev_get_drvdata(pdev->dev.parent);728 info->irq = -1;729 730 platform_set_drvdata(pdev, info);731 732 info->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb");733 if (IS_ERR(info->channel_vusb)) {734 if (PTR_ERR(info->channel_vusb) == -ENODEV)735 return -EPROBE_DEFER;736 return PTR_ERR(info->channel_vusb);737 }738 739 info->channel_vadp = devm_iio_channel_get(&pdev->dev, "vadp");740 if (IS_ERR(info->channel_vadp)) {741 if (PTR_ERR(info->channel_vadp) == -ENODEV)742 return -EPROBE_DEFER;743 return PTR_ERR(info->channel_vadp);744 }745 746 ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v);747 if (ret)748 return ret;749 750 if (!(v & FG_ENABLE)) {751 /* E.g. the vendor kernels of various Kobo and Tolino Ebook752 * readers disable the fuel gauge on shutdown. If a kernel753 * without fuel gauge support is booted after that, the fuel754 * gauge will get decalibrated.755 */756 dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n");757 dev_info(&pdev->dev, "Expect imprecise results\n");758 regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL,759 FG_ENABLE, FG_ENABLE);760 }761 762 psy_cfg.drv_data = info;763 info->battery = devm_power_supply_register(&pdev->dev,764 &rn5t618_battery_desc,765 &psy_cfg);766 if (IS_ERR(info->battery)) {767 ret = PTR_ERR(info->battery);768 dev_err(&pdev->dev, "failed to register battery: %d\n", ret);769 return ret;770 }771 772 info->adp = devm_power_supply_register(&pdev->dev,773 &rn5t618_adp_desc,774 &psy_cfg);775 if (IS_ERR(info->adp)) {776 ret = PTR_ERR(info->adp);777 dev_err(&pdev->dev, "failed to register adp: %d\n", ret);778 return ret;779 }780 781 info->usb = devm_power_supply_register(&pdev->dev,782 &rn5t618_usb_desc,783 &psy_cfg);784 if (IS_ERR(info->usb)) {785 ret = PTR_ERR(info->usb);786 dev_err(&pdev->dev, "failed to register usb: %d\n", ret);787 return ret;788 }789 790 if (info->rn5t618->irq_data)791 info->irq = regmap_irq_get_virq(info->rn5t618->irq_data,792 RN5T618_IRQ_CHG);793 794 if (info->irq < 0)795 info->irq = -1;796 else {797 ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,798 rn5t618_charger_irq,799 IRQF_ONESHOT,800 "rn5t618_power",801 &pdev->dev);802 803 if (ret < 0) {804 dev_err(&pdev->dev, "request IRQ:%d fail\n",805 info->irq);806 info->irq = -1;807 }808 }809 810 return 0;811}812 813static struct platform_driver rn5t618_power_driver = {814 .driver = {815 .name = "rn5t618-power",816 },817 .probe = rn5t618_power_probe,818};819 820module_platform_driver(rn5t618_power_driver);821MODULE_ALIAS("platform:rn5t618-power");822MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");823MODULE_LICENSE("GPL");824