Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Power supply driver for the RICOH RN5T618 power management chip family
0004  *
0005  * Copyright (C) 2020 Andreas Kemnade
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/device.h>
0010 #include <linux/bitops.h>
0011 #include <linux/errno.h>
0012 #include <linux/iio/consumer.h>
0013 #include <linux/init.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/module.h>
0016 #include <linux/mfd/rn5t618.h>
0017 #include <linux/of_device.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/power_supply.h>
0020 #include <linux/regmap.h>
0021 #include <linux/slab.h>
0022 
0023 #define CHG_STATE_ADP_INPUT 0x40
0024 #define CHG_STATE_USB_INPUT 0x80
0025 #define CHG_STATE_MASK  0x1f
0026 #define CHG_STATE_CHG_OFF   0
0027 #define CHG_STATE_CHG_READY_VADP    1
0028 #define CHG_STATE_CHG_TRICKLE   2
0029 #define CHG_STATE_CHG_RAPID 3
0030 #define CHG_STATE_CHG_COMPLETE  4
0031 #define CHG_STATE_SUSPEND   5
0032 #define CHG_STATE_VCHG_OVER_VOL 6
0033 #define CHG_STATE_BAT_ERROR 7
0034 #define CHG_STATE_NO_BAT    8
0035 #define CHG_STATE_BAT_OVER_VOL  9
0036 #define CHG_STATE_BAT_TEMP_ERR  10
0037 #define CHG_STATE_DIE_ERR   11
0038 #define CHG_STATE_DIE_SHUTDOWN  12
0039 #define CHG_STATE_NO_BAT2   13
0040 #define CHG_STATE_CHG_READY_VUSB    14
0041 
0042 #define GCHGDET_TYPE_MASK 0x30
0043 #define GCHGDET_TYPE_SDP 0x00
0044 #define GCHGDET_TYPE_CDP 0x10
0045 #define GCHGDET_TYPE_DCP 0x20
0046 
0047 #define FG_ENABLE 1
0048 
0049 /*
0050  * Formula seems accurate for battery current, but for USB current around 70mA
0051  * per step was seen on Kobo Clara HD but all sources show the same formula
0052  * also fur USB current. To avoid accidentially unwanted high currents we stick
0053  * to that formula
0054  */
0055 #define TO_CUR_REG(x) ((x) / 100000 - 1)
0056 #define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
0057 #define CHG_MIN_CUR 100000
0058 #define CHG_MAX_CUR 1800000
0059 #define ADP_MAX_CUR 2500000
0060 #define USB_MAX_CUR 1400000
0061 
0062 
0063 struct rn5t618_power_info {
0064     struct rn5t618 *rn5t618;
0065     struct platform_device *pdev;
0066     struct power_supply *battery;
0067     struct power_supply *usb;
0068     struct power_supply *adp;
0069     struct iio_channel *channel_vusb;
0070     struct iio_channel *channel_vadp;
0071     int irq;
0072 };
0073 
0074 static enum power_supply_usb_type rn5t618_usb_types[] = {
0075     POWER_SUPPLY_USB_TYPE_SDP,
0076     POWER_SUPPLY_USB_TYPE_DCP,
0077     POWER_SUPPLY_USB_TYPE_CDP,
0078     POWER_SUPPLY_USB_TYPE_UNKNOWN
0079 };
0080 
0081 static enum power_supply_property rn5t618_usb_props[] = {
0082     /* input current limit is not very accurate */
0083     POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
0084     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0085     POWER_SUPPLY_PROP_STATUS,
0086     POWER_SUPPLY_PROP_USB_TYPE,
0087     POWER_SUPPLY_PROP_ONLINE,
0088 };
0089 
0090 static enum power_supply_property rn5t618_adp_props[] = {
0091     /* input current limit is not very accurate */
0092     POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
0093     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0094     POWER_SUPPLY_PROP_STATUS,
0095     POWER_SUPPLY_PROP_ONLINE,
0096 };
0097 
0098 
0099 static enum power_supply_property rn5t618_battery_props[] = {
0100     POWER_SUPPLY_PROP_STATUS,
0101     POWER_SUPPLY_PROP_PRESENT,
0102     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0103     POWER_SUPPLY_PROP_CURRENT_NOW,
0104     POWER_SUPPLY_PROP_CAPACITY,
0105     POWER_SUPPLY_PROP_TEMP,
0106     POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
0107     POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
0108     POWER_SUPPLY_PROP_TECHNOLOGY,
0109     POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
0110     POWER_SUPPLY_PROP_CHARGE_FULL,
0111     POWER_SUPPLY_PROP_CHARGE_NOW,
0112 };
0113 
0114 static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info,
0115                       u8 reg, u16 *result)
0116 {
0117     int ret, i;
0118     u8 data[2];
0119     u16 old, new;
0120 
0121     old = 0;
0122     /* Prevent races when registers are changing. */
0123     for (i = 0; i < 3; i++) {
0124         ret = regmap_bulk_read(info->rn5t618->regmap,
0125                        reg, data, sizeof(data));
0126         if (ret)
0127             return ret;
0128 
0129         new = data[0] << 8;
0130         new |= data[1];
0131         if (new == old)
0132             break;
0133 
0134         old = new;
0135     }
0136 
0137     *result = new;
0138 
0139     return 0;
0140 }
0141 
0142 static int rn5t618_decode_status(unsigned int status)
0143 {
0144     switch (status & CHG_STATE_MASK) {
0145     case CHG_STATE_CHG_OFF:
0146     case CHG_STATE_SUSPEND:
0147     case CHG_STATE_VCHG_OVER_VOL:
0148     case CHG_STATE_DIE_SHUTDOWN:
0149         return POWER_SUPPLY_STATUS_DISCHARGING;
0150 
0151     case CHG_STATE_CHG_TRICKLE:
0152     case CHG_STATE_CHG_RAPID:
0153         return POWER_SUPPLY_STATUS_CHARGING;
0154 
0155     case CHG_STATE_CHG_COMPLETE:
0156         return POWER_SUPPLY_STATUS_FULL;
0157 
0158     default:
0159         return POWER_SUPPLY_STATUS_NOT_CHARGING;
0160     }
0161 }
0162 
0163 static int rn5t618_battery_status(struct rn5t618_power_info *info,
0164                   union power_supply_propval *val)
0165 {
0166     unsigned int v;
0167     int ret;
0168 
0169     ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
0170     if (ret)
0171         return ret;
0172 
0173     val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
0174 
0175     if (v & 0xc0) { /* USB or ADP plugged */
0176         val->intval = rn5t618_decode_status(v);
0177     } else
0178         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0179 
0180     return ret;
0181 }
0182 
0183 static int rn5t618_battery_present(struct rn5t618_power_info *info,
0184                    union power_supply_propval *val)
0185 {
0186     unsigned int v;
0187     int ret;
0188 
0189     ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
0190     if (ret)
0191         return ret;
0192 
0193     v &= CHG_STATE_MASK;
0194     if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2))
0195         val->intval = 0;
0196     else
0197         val->intval = 1;
0198 
0199     return ret;
0200 }
0201 
0202 static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info,
0203                        union power_supply_propval *val)
0204 {
0205     u16 res;
0206     int ret;
0207 
0208     ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res);
0209     if (ret)
0210         return ret;
0211 
0212     val->intval = res * 2 * 2500 / 4095 * 1000;
0213 
0214     return 0;
0215 }
0216 
0217 static int rn5t618_battery_current_now(struct rn5t618_power_info *info,
0218                        union power_supply_propval *val)
0219 {
0220     u16 res;
0221     int ret;
0222 
0223     ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res);
0224     if (ret)
0225         return ret;
0226 
0227     /* current is negative when discharging */
0228     val->intval = sign_extend32(res, 13) * 1000;
0229 
0230     return 0;
0231 }
0232 
0233 static int rn5t618_battery_capacity(struct rn5t618_power_info *info,
0234                     union power_supply_propval *val)
0235 {
0236     unsigned int v;
0237     int ret;
0238 
0239     ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v);
0240     if (ret)
0241         return ret;
0242 
0243     val->intval = v;
0244 
0245     return 0;
0246 }
0247 
0248 static int rn5t618_battery_temp(struct rn5t618_power_info *info,
0249                 union power_supply_propval *val)
0250 {
0251     u16 res;
0252     int ret;
0253 
0254     ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res);
0255     if (ret)
0256         return ret;
0257 
0258     val->intval = sign_extend32(res, 11) * 10 / 16;
0259 
0260     return 0;
0261 }
0262 
0263 static int rn5t618_battery_tte(struct rn5t618_power_info *info,
0264                    union power_supply_propval *val)
0265 {
0266     u16 res;
0267     int ret;
0268 
0269     ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);
0270     if (ret)
0271         return ret;
0272 
0273     if (res == 65535)
0274         return -ENODATA;
0275 
0276     val->intval = res * 60;
0277 
0278     return 0;
0279 }
0280 
0281 static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
0282                    union power_supply_propval *val)
0283 {
0284     u16 res;
0285     int ret;
0286 
0287     ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res);
0288     if (ret)
0289         return ret;
0290 
0291     if (res == 65535)
0292         return -ENODATA;
0293 
0294     val->intval = res * 60;
0295 
0296     return 0;
0297 }
0298 
0299 static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
0300                 const union power_supply_propval *val)
0301 {
0302     if (val->intval < CHG_MIN_CUR)
0303         return -EINVAL;
0304 
0305     if (val->intval >= CHG_MAX_CUR)
0306         return -EINVAL;
0307 
0308     return regmap_update_bits(info->rn5t618->regmap,
0309                   RN5T618_CHGISET,
0310                   0x1F, TO_CUR_REG(val->intval));
0311 }
0312 
0313 static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
0314                          union power_supply_propval *val)
0315 {
0316     unsigned int regval;
0317     int ret;
0318 
0319     ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
0320               &regval);
0321     if (ret < 0)
0322         return ret;
0323 
0324     val->intval = FROM_CUR_REG(regval);
0325 
0326     return 0;
0327 }
0328 
0329 static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
0330                        union power_supply_propval *val)
0331 {
0332     u16 res;
0333     int ret;
0334 
0335     ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res);
0336     if (ret)
0337         return ret;
0338 
0339     val->intval = res * 1000;
0340 
0341     return 0;
0342 }
0343 
0344 static int rn5t618_battery_charge_now(struct rn5t618_power_info *info,
0345                       union power_supply_propval *val)
0346 {
0347     u16 res;
0348     int ret;
0349 
0350     ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res);
0351     if (ret)
0352         return ret;
0353 
0354     val->intval = res * 1000;
0355 
0356     return 0;
0357 }
0358 
0359 static int rn5t618_battery_get_property(struct power_supply *psy,
0360                     enum power_supply_property psp,
0361                     union power_supply_propval *val)
0362 {
0363     int ret = 0;
0364     struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
0365 
0366     switch (psp) {
0367     case POWER_SUPPLY_PROP_STATUS:
0368         ret = rn5t618_battery_status(info, val);
0369         break;
0370     case POWER_SUPPLY_PROP_PRESENT:
0371         ret = rn5t618_battery_present(info, val);
0372         break;
0373     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0374         ret = rn5t618_battery_voltage_now(info, val);
0375         break;
0376     case POWER_SUPPLY_PROP_CURRENT_NOW:
0377         ret = rn5t618_battery_current_now(info, val);
0378         break;
0379     case POWER_SUPPLY_PROP_CAPACITY:
0380         ret = rn5t618_battery_capacity(info, val);
0381         break;
0382     case POWER_SUPPLY_PROP_TEMP:
0383         ret = rn5t618_battery_temp(info, val);
0384         break;
0385     case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
0386         ret = rn5t618_battery_tte(info, val);
0387         break;
0388     case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
0389         ret = rn5t618_battery_ttf(info, val);
0390         break;
0391     case POWER_SUPPLY_PROP_TECHNOLOGY:
0392         val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
0393         break;
0394     case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0395         ret = rn5t618_battery_get_current_limit(info, val);
0396         break;
0397     case POWER_SUPPLY_PROP_CHARGE_FULL:
0398         ret = rn5t618_battery_charge_full(info, val);
0399         break;
0400     case POWER_SUPPLY_PROP_CHARGE_NOW:
0401         ret = rn5t618_battery_charge_now(info, val);
0402         break;
0403     default:
0404         return -EINVAL;
0405     }
0406 
0407     return ret;
0408 }
0409 
0410 static int rn5t618_battery_set_property(struct power_supply *psy,
0411                     enum power_supply_property psp,
0412                     const union power_supply_propval *val)
0413 {
0414     struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
0415 
0416     switch (psp) {
0417     case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0418         return rn5t618_battery_set_current_limit(info, val);
0419     default:
0420         return -EINVAL;
0421     }
0422 }
0423 
0424 static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
0425                         enum power_supply_property psp)
0426 {
0427     switch (psp) {
0428     case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0429         return true;
0430     default:
0431         return false;
0432     }
0433 }
0434 
0435 static int rn5t618_adp_get_property(struct power_supply *psy,
0436                     enum power_supply_property psp,
0437                     union power_supply_propval *val)
0438 {
0439     struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
0440     unsigned int chgstate;
0441     unsigned int regval;
0442     bool online;
0443     int ret;
0444 
0445     ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
0446     if (ret)
0447         return ret;
0448 
0449     online = !!(chgstate & CHG_STATE_ADP_INPUT);
0450 
0451     switch (psp) {
0452     case POWER_SUPPLY_PROP_ONLINE:
0453         val->intval = online;
0454         break;
0455     case POWER_SUPPLY_PROP_STATUS:
0456         if (!online) {
0457             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0458             break;
0459         }
0460         val->intval = rn5t618_decode_status(chgstate);
0461         if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
0462             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0463 
0464         break;
0465     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0466         ret = regmap_read(info->rn5t618->regmap,
0467                   RN5T618_REGISET1, &regval);
0468         if (ret < 0)
0469             return ret;
0470 
0471         val->intval = FROM_CUR_REG(regval);
0472         break;
0473     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0474         if (!info->channel_vadp)
0475             return -ENODATA;
0476 
0477         ret = iio_read_channel_processed_scale(info->channel_vadp, &val->intval, 1000);
0478         if (ret < 0)
0479             return ret;
0480 
0481         break;
0482     default:
0483         return -EINVAL;
0484     }
0485 
0486     return 0;
0487 }
0488 
0489 static int rn5t618_adp_set_property(struct power_supply *psy,
0490                     enum power_supply_property psp,
0491                     const union power_supply_propval *val)
0492 {
0493     struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
0494     int ret;
0495 
0496     switch (psp) {
0497     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0498         if (val->intval > ADP_MAX_CUR)
0499             return -EINVAL;
0500 
0501         if (val->intval < CHG_MIN_CUR)
0502             return -EINVAL;
0503 
0504         ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
0505                    TO_CUR_REG(val->intval));
0506         if (ret < 0)
0507             return ret;
0508 
0509         break;
0510     default:
0511         return -EINVAL;
0512     }
0513 
0514     return 0;
0515 }
0516 
0517 static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
0518                          enum power_supply_property psp)
0519 {
0520     switch (psp) {
0521     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0522         return true;
0523     default:
0524         return false;
0525     }
0526 }
0527 
0528 static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
0529                 union power_supply_propval *val)
0530 {
0531     unsigned int regval;
0532     int ret;
0533 
0534     ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
0535     if (ret < 0)
0536         return ret;
0537 
0538     switch (regval & GCHGDET_TYPE_MASK) {
0539     case GCHGDET_TYPE_SDP:
0540         val->intval = POWER_SUPPLY_USB_TYPE_SDP;
0541         break;
0542     case GCHGDET_TYPE_CDP:
0543         val->intval = POWER_SUPPLY_USB_TYPE_CDP;
0544         break;
0545     case GCHGDET_TYPE_DCP:
0546         val->intval = POWER_SUPPLY_USB_TYPE_DCP;
0547         break;
0548     default:
0549         val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
0550     }
0551 
0552     return 0;
0553 }
0554 
0555 static int rn5t618_usb_get_property(struct power_supply *psy,
0556                     enum power_supply_property psp,
0557                     union power_supply_propval *val)
0558 {
0559     struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
0560     unsigned int chgstate;
0561     unsigned int regval;
0562     bool online;
0563     int ret;
0564 
0565     ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
0566     if (ret)
0567         return ret;
0568 
0569     online = !!(chgstate & CHG_STATE_USB_INPUT);
0570 
0571     switch (psp) {
0572     case POWER_SUPPLY_PROP_ONLINE:
0573         val->intval = online;
0574         break;
0575     case POWER_SUPPLY_PROP_STATUS:
0576         if (!online) {
0577             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0578             break;
0579         }
0580         val->intval = rn5t618_decode_status(chgstate);
0581         if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
0582             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0583 
0584         break;
0585     case POWER_SUPPLY_PROP_USB_TYPE:
0586         if (!online || (info->rn5t618->variant != RC5T619))
0587             return -ENODATA;
0588 
0589         return rc5t619_usb_get_type(info, val);
0590     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0591         ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
0592                   &regval);
0593         if (ret < 0)
0594             return ret;
0595 
0596         val->intval = 0;
0597         if (regval & 2) {
0598             ret = regmap_read(info->rn5t618->regmap,
0599                       RN5T618_REGISET2,
0600                       &regval);
0601             if (ret < 0)
0602                 return ret;
0603 
0604             val->intval = FROM_CUR_REG(regval);
0605         }
0606         break;
0607     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0608         if (!info->channel_vusb)
0609             return -ENODATA;
0610 
0611         ret = iio_read_channel_processed_scale(info->channel_vusb, &val->intval, 1000);
0612         if (ret < 0)
0613             return ret;
0614 
0615         break;
0616     default:
0617         return -EINVAL;
0618     }
0619 
0620     return 0;
0621 }
0622 
0623 static int rn5t618_usb_set_property(struct power_supply *psy,
0624                     enum power_supply_property psp,
0625                     const union power_supply_propval *val)
0626 {
0627     struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
0628     int ret;
0629 
0630     switch (psp) {
0631     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0632         if (val->intval > USB_MAX_CUR)
0633             return -EINVAL;
0634 
0635         if (val->intval < CHG_MIN_CUR)
0636             return -EINVAL;
0637 
0638         ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
0639                    0xE0 | TO_CUR_REG(val->intval));
0640         if (ret < 0)
0641             return ret;
0642 
0643         break;
0644     default:
0645         return -EINVAL;
0646     }
0647 
0648     return 0;
0649 }
0650 
0651 static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
0652                          enum power_supply_property psp)
0653 {
0654     switch (psp) {
0655     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0656         return true;
0657     default:
0658         return false;
0659     }
0660 }
0661 
0662 static const struct power_supply_desc rn5t618_battery_desc = {
0663     .name                   = "rn5t618-battery",
0664     .type                   = POWER_SUPPLY_TYPE_BATTERY,
0665     .properties             = rn5t618_battery_props,
0666     .num_properties         = ARRAY_SIZE(rn5t618_battery_props),
0667     .get_property           = rn5t618_battery_get_property,
0668     .set_property           = rn5t618_battery_set_property,
0669     .property_is_writeable  = rn5t618_battery_property_is_writeable,
0670 };
0671 
0672 static const struct power_supply_desc rn5t618_adp_desc = {
0673     .name                   = "rn5t618-adp",
0674     .type                   = POWER_SUPPLY_TYPE_MAINS,
0675     .properties             = rn5t618_adp_props,
0676     .num_properties         = ARRAY_SIZE(rn5t618_adp_props),
0677     .get_property           = rn5t618_adp_get_property,
0678     .set_property           = rn5t618_adp_set_property,
0679     .property_is_writeable  = rn5t618_adp_property_is_writeable,
0680 };
0681 
0682 static const struct power_supply_desc rn5t618_usb_desc = {
0683     .name                   = "rn5t618-usb",
0684     .type                   = POWER_SUPPLY_TYPE_USB,
0685     .usb_types      = rn5t618_usb_types,
0686     .num_usb_types      = ARRAY_SIZE(rn5t618_usb_types),
0687     .properties             = rn5t618_usb_props,
0688     .num_properties         = ARRAY_SIZE(rn5t618_usb_props),
0689     .get_property           = rn5t618_usb_get_property,
0690     .set_property           = rn5t618_usb_set_property,
0691     .property_is_writeable  = rn5t618_usb_property_is_writeable,
0692 };
0693 
0694 static irqreturn_t rn5t618_charger_irq(int irq, void *data)
0695 {
0696     struct device *dev = data;
0697     struct rn5t618_power_info *info = dev_get_drvdata(dev);
0698 
0699     unsigned int ctrl, stat1, stat2, err;
0700 
0701     regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err);
0702     regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl);
0703     regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1);
0704     regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2);
0705 
0706     regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0);
0707     regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0);
0708     regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0);
0709     regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0);
0710 
0711     dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n",
0712         err, ctrl, stat1, stat2);
0713 
0714     power_supply_changed(info->usb);
0715     power_supply_changed(info->adp);
0716     power_supply_changed(info->battery);
0717 
0718     return IRQ_HANDLED;
0719 }
0720 
0721 static int rn5t618_power_probe(struct platform_device *pdev)
0722 {
0723     int ret = 0;
0724     unsigned int v;
0725     struct power_supply_config psy_cfg = {};
0726     struct rn5t618_power_info *info;
0727 
0728     info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
0729     if (!info)
0730         return -ENOMEM;
0731 
0732     info->pdev = pdev;
0733     info->rn5t618 = dev_get_drvdata(pdev->dev.parent);
0734     info->irq = -1;
0735 
0736     platform_set_drvdata(pdev, info);
0737 
0738     info->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb");
0739     if (IS_ERR(info->channel_vusb)) {
0740         if (PTR_ERR(info->channel_vusb) == -ENODEV)
0741             return -EPROBE_DEFER;
0742         return PTR_ERR(info->channel_vusb);
0743     }
0744 
0745     info->channel_vadp = devm_iio_channel_get(&pdev->dev, "vadp");
0746     if (IS_ERR(info->channel_vadp)) {
0747         if (PTR_ERR(info->channel_vadp) == -ENODEV)
0748             return -EPROBE_DEFER;
0749         return PTR_ERR(info->channel_vadp);
0750     }
0751 
0752     ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v);
0753     if (ret)
0754         return ret;
0755 
0756     if (!(v & FG_ENABLE)) {
0757         /* E.g. the vendor kernels of various Kobo and Tolino Ebook
0758          * readers disable the fuel gauge on shutdown. If a kernel
0759          * without fuel gauge support is booted after that, the fuel
0760          * gauge will get decalibrated.
0761          */
0762         dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n");
0763         dev_info(&pdev->dev, "Expect imprecise results\n");
0764         regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL,
0765                    FG_ENABLE, FG_ENABLE);
0766     }
0767 
0768     psy_cfg.drv_data = info;
0769     info->battery = devm_power_supply_register(&pdev->dev,
0770                            &rn5t618_battery_desc,
0771                            &psy_cfg);
0772     if (IS_ERR(info->battery)) {
0773         ret = PTR_ERR(info->battery);
0774         dev_err(&pdev->dev, "failed to register battery: %d\n", ret);
0775         return ret;
0776     }
0777 
0778     info->adp = devm_power_supply_register(&pdev->dev,
0779                            &rn5t618_adp_desc,
0780                            &psy_cfg);
0781     if (IS_ERR(info->adp)) {
0782         ret = PTR_ERR(info->adp);
0783         dev_err(&pdev->dev, "failed to register adp: %d\n", ret);
0784         return ret;
0785     }
0786 
0787     info->usb = devm_power_supply_register(&pdev->dev,
0788                            &rn5t618_usb_desc,
0789                            &psy_cfg);
0790     if (IS_ERR(info->usb)) {
0791         ret = PTR_ERR(info->usb);
0792         dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
0793         return ret;
0794     }
0795 
0796     if (info->rn5t618->irq_data)
0797         info->irq = regmap_irq_get_virq(info->rn5t618->irq_data,
0798                         RN5T618_IRQ_CHG);
0799 
0800     if (info->irq < 0)
0801         info->irq = -1;
0802     else {
0803         ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
0804                         rn5t618_charger_irq,
0805                         IRQF_ONESHOT,
0806                         "rn5t618_power",
0807                         &pdev->dev);
0808 
0809         if (ret < 0) {
0810             dev_err(&pdev->dev, "request IRQ:%d fail\n",
0811                 info->irq);
0812             info->irq = -1;
0813         }
0814     }
0815 
0816     return 0;
0817 }
0818 
0819 static struct platform_driver rn5t618_power_driver = {
0820     .driver = {
0821         .name   = "rn5t618-power",
0822     },
0823     .probe = rn5t618_power_probe,
0824 };
0825 
0826 module_platform_driver(rn5t618_power_driver);
0827 MODULE_ALIAS("platform:rn5t618-power");
0828 MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");
0829 MODULE_LICENSE("GPL");