Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Battery driver for Maxim MAX8925
0004  *
0005  * Copyright (c) 2009-2010 Marvell International Ltd.
0006  *  Haojian Zhuang <haojian.zhuang@marvell.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/err.h>
0011 #include <linux/slab.h>
0012 #include <linux/of.h>
0013 #include <linux/i2c.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/power_supply.h>
0017 #include <linux/mfd/max8925.h>
0018 
0019 /* registers in GPM */
0020 #define MAX8925_OUT5VEN         0x54
0021 #define MAX8925_OUT3VEN         0x58
0022 #define MAX8925_CHG_CNTL1       0x7c
0023 
0024 /* bits definition */
0025 #define MAX8925_CHG_STAT_VSYSLOW    (1 << 0)
0026 #define MAX8925_CHG_STAT_MODE_MASK  (3 << 2)
0027 #define MAX8925_CHG_STAT_EN_MASK    (1 << 4)
0028 #define MAX8925_CHG_MBDET       (1 << 1)
0029 #define MAX8925_CHG_AC_RANGE_MASK   (3 << 6)
0030 
0031 /* registers in ADC */
0032 #define MAX8925_ADC_RES_CNFG1       0x06
0033 #define MAX8925_ADC_AVG_CNFG1       0x07
0034 #define MAX8925_ADC_ACQ_CNFG1       0x08
0035 #define MAX8925_ADC_ACQ_CNFG2       0x09
0036 /* 2 bytes registers in below. MSB is 1st, LSB is 2nd. */
0037 #define MAX8925_ADC_AUX2        0x62
0038 #define MAX8925_ADC_VCHG        0x64
0039 #define MAX8925_ADC_VBBATT      0x66
0040 #define MAX8925_ADC_VMBATT      0x68
0041 #define MAX8925_ADC_ISNS        0x6a
0042 #define MAX8925_ADC_THM         0x6c
0043 #define MAX8925_ADC_TDIE        0x6e
0044 #define MAX8925_CMD_AUX2        0xc8
0045 #define MAX8925_CMD_VCHG        0xd0
0046 #define MAX8925_CMD_VBBATT      0xd8
0047 #define MAX8925_CMD_VMBATT      0xe0
0048 #define MAX8925_CMD_ISNS        0xe8
0049 #define MAX8925_CMD_THM         0xf0
0050 #define MAX8925_CMD_TDIE        0xf8
0051 
0052 enum {
0053     MEASURE_AUX2,
0054     MEASURE_VCHG,
0055     MEASURE_VBBATT,
0056     MEASURE_VMBATT,
0057     MEASURE_ISNS,
0058     MEASURE_THM,
0059     MEASURE_TDIE,
0060     MEASURE_MAX,
0061 };
0062 
0063 struct max8925_power_info {
0064     struct max8925_chip *chip;
0065     struct i2c_client   *gpm;
0066     struct i2c_client   *adc;
0067 
0068     struct power_supply *ac;
0069     struct power_supply *usb;
0070     struct power_supply *battery;
0071     int         irq_base;
0072     unsigned        ac_online:1;
0073     unsigned        usb_online:1;
0074     unsigned        bat_online:1;
0075     unsigned        chg_mode:2;
0076     unsigned        batt_detect:1;  /* detecing MB by ID pin */
0077     unsigned        topoff_threshold:2;
0078     unsigned        fast_charge:3;
0079     unsigned        no_temp_support:1;
0080     unsigned        no_insert_detect:1;
0081 
0082     int (*set_charger) (int);
0083 };
0084 
0085 static int __set_charger(struct max8925_power_info *info, int enable)
0086 {
0087     struct max8925_chip *chip = info->chip;
0088     if (enable) {
0089         /* enable charger in platform */
0090         if (info->set_charger)
0091             info->set_charger(1);
0092         /* enable charger */
0093         max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 0);
0094     } else {
0095         /* disable charge */
0096         max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7);
0097         if (info->set_charger)
0098             info->set_charger(0);
0099     }
0100     dev_dbg(chip->dev, "%s\n", (enable) ? "Enable charger"
0101         : "Disable charger");
0102     return 0;
0103 }
0104 
0105 static irqreturn_t max8925_charger_handler(int irq, void *data)
0106 {
0107     struct max8925_power_info *info = (struct max8925_power_info *)data;
0108     struct max8925_chip *chip = info->chip;
0109 
0110     switch (irq - chip->irq_base) {
0111     case MAX8925_IRQ_VCHG_DC_R:
0112         info->ac_online = 1;
0113         __set_charger(info, 1);
0114         dev_dbg(chip->dev, "Adapter inserted\n");
0115         break;
0116     case MAX8925_IRQ_VCHG_DC_F:
0117         info->ac_online = 0;
0118         __set_charger(info, 0);
0119         dev_dbg(chip->dev, "Adapter removed\n");
0120         break;
0121     case MAX8925_IRQ_VCHG_THM_OK_F:
0122         /* Battery is not ready yet */
0123         dev_dbg(chip->dev, "Battery temperature is out of range\n");
0124         fallthrough;
0125     case MAX8925_IRQ_VCHG_DC_OVP:
0126         dev_dbg(chip->dev, "Error detection\n");
0127         __set_charger(info, 0);
0128         break;
0129     case MAX8925_IRQ_VCHG_THM_OK_R:
0130         /* Battery is ready now */
0131         dev_dbg(chip->dev, "Battery temperature is in range\n");
0132         break;
0133     case MAX8925_IRQ_VCHG_SYSLOW_R:
0134         /* VSYS is low */
0135         dev_info(chip->dev, "Sys power is too low\n");
0136         break;
0137     case MAX8925_IRQ_VCHG_SYSLOW_F:
0138         dev_dbg(chip->dev, "Sys power is above low threshold\n");
0139         break;
0140     case MAX8925_IRQ_VCHG_DONE:
0141         __set_charger(info, 0);
0142         dev_dbg(chip->dev, "Charging is done\n");
0143         break;
0144     case MAX8925_IRQ_VCHG_TOPOFF:
0145         dev_dbg(chip->dev, "Charging in top-off mode\n");
0146         break;
0147     case MAX8925_IRQ_VCHG_TMR_FAULT:
0148         __set_charger(info, 0);
0149         dev_dbg(chip->dev, "Safe timer is expired\n");
0150         break;
0151     case MAX8925_IRQ_VCHG_RST:
0152         __set_charger(info, 0);
0153         dev_dbg(chip->dev, "Charger is reset\n");
0154         break;
0155     }
0156     return IRQ_HANDLED;
0157 }
0158 
0159 static int start_measure(struct max8925_power_info *info, int type)
0160 {
0161     unsigned char buf[2] = {0, 0};
0162     int meas_cmd;
0163     int meas_reg = 0, ret;
0164 
0165     switch (type) {
0166     case MEASURE_VCHG:
0167         meas_cmd = MAX8925_CMD_VCHG;
0168         meas_reg = MAX8925_ADC_VCHG;
0169         break;
0170     case MEASURE_VBBATT:
0171         meas_cmd = MAX8925_CMD_VBBATT;
0172         meas_reg = MAX8925_ADC_VBBATT;
0173         break;
0174     case MEASURE_VMBATT:
0175         meas_cmd = MAX8925_CMD_VMBATT;
0176         meas_reg = MAX8925_ADC_VMBATT;
0177         break;
0178     case MEASURE_ISNS:
0179         meas_cmd = MAX8925_CMD_ISNS;
0180         meas_reg = MAX8925_ADC_ISNS;
0181         break;
0182     default:
0183         return -EINVAL;
0184     }
0185 
0186     max8925_reg_write(info->adc, meas_cmd, 0);
0187     max8925_bulk_read(info->adc, meas_reg, 2, buf);
0188     ret = ((buf[0]<<8) | buf[1]) >> 4;
0189 
0190     return ret;
0191 }
0192 
0193 static int max8925_ac_get_prop(struct power_supply *psy,
0194                    enum power_supply_property psp,
0195                    union power_supply_propval *val)
0196 {
0197     struct max8925_power_info *info = dev_get_drvdata(psy->dev.parent);
0198     int ret = 0;
0199 
0200     switch (psp) {
0201     case POWER_SUPPLY_PROP_ONLINE:
0202         val->intval = info->ac_online;
0203         break;
0204     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0205         if (info->ac_online) {
0206             ret = start_measure(info, MEASURE_VCHG);
0207             if (ret >= 0) {
0208                 val->intval = ret * 2000;   /* unit is uV */
0209                 goto out;
0210             }
0211         }
0212         ret = -ENODATA;
0213         break;
0214     default:
0215         ret = -ENODEV;
0216         break;
0217     }
0218 out:
0219     return ret;
0220 }
0221 
0222 static enum power_supply_property max8925_ac_props[] = {
0223     POWER_SUPPLY_PROP_ONLINE,
0224     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0225 };
0226 
0227 static int max8925_usb_get_prop(struct power_supply *psy,
0228                 enum power_supply_property psp,
0229                 union power_supply_propval *val)
0230 {
0231     struct max8925_power_info *info = dev_get_drvdata(psy->dev.parent);
0232     int ret = 0;
0233 
0234     switch (psp) {
0235     case POWER_SUPPLY_PROP_ONLINE:
0236         val->intval = info->usb_online;
0237         break;
0238     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0239         if (info->usb_online) {
0240             ret = start_measure(info, MEASURE_VCHG);
0241             if (ret >= 0) {
0242                 val->intval = ret * 2000;   /* unit is uV */
0243                 goto out;
0244             }
0245         }
0246         ret = -ENODATA;
0247         break;
0248     default:
0249         ret = -ENODEV;
0250         break;
0251     }
0252 out:
0253     return ret;
0254 }
0255 
0256 static enum power_supply_property max8925_usb_props[] = {
0257     POWER_SUPPLY_PROP_ONLINE,
0258     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0259 };
0260 
0261 static int max8925_bat_get_prop(struct power_supply *psy,
0262                 enum power_supply_property psp,
0263                 union power_supply_propval *val)
0264 {
0265     struct max8925_power_info *info = dev_get_drvdata(psy->dev.parent);
0266     int ret = 0;
0267 
0268     switch (psp) {
0269     case POWER_SUPPLY_PROP_ONLINE:
0270         val->intval = info->bat_online;
0271         break;
0272     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0273         if (info->bat_online) {
0274             ret = start_measure(info, MEASURE_VMBATT);
0275             if (ret >= 0) {
0276                 val->intval = ret * 2000;   /* unit is uV */
0277                 ret = 0;
0278                 break;
0279             }
0280         }
0281         ret = -ENODATA;
0282         break;
0283     case POWER_SUPPLY_PROP_CURRENT_NOW:
0284         if (info->bat_online) {
0285             ret = start_measure(info, MEASURE_ISNS);
0286             if (ret >= 0) {
0287                 /* assume r_sns is 0.02 */
0288                 ret = ((ret * 6250) - 3125) /* uA */;
0289                 val->intval = 0;
0290                 if (ret > 0)
0291                     val->intval = ret; /* unit is mA */
0292                 ret = 0;
0293                 break;
0294             }
0295         }
0296         ret = -ENODATA;
0297         break;
0298     case POWER_SUPPLY_PROP_CHARGE_TYPE:
0299         if (!info->bat_online) {
0300             ret = -ENODATA;
0301             break;
0302         }
0303         ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
0304         ret = (ret & MAX8925_CHG_STAT_MODE_MASK) >> 2;
0305         switch (ret) {
0306         case 1:
0307             val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
0308             break;
0309         case 0:
0310         case 2:
0311             val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0312             break;
0313         case 3:
0314             val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
0315             break;
0316         }
0317         ret = 0;
0318         break;
0319     case POWER_SUPPLY_PROP_STATUS:
0320         if (!info->bat_online) {
0321             ret = -ENODATA;
0322             break;
0323         }
0324         ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
0325         if (info->usb_online || info->ac_online) {
0326             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0327             if (ret & MAX8925_CHG_STAT_EN_MASK)
0328                 val->intval = POWER_SUPPLY_STATUS_CHARGING;
0329         } else
0330             val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0331         ret = 0;
0332         break;
0333     default:
0334         ret = -ENODEV;
0335         break;
0336     }
0337     return ret;
0338 }
0339 
0340 static enum power_supply_property max8925_battery_props[] = {
0341     POWER_SUPPLY_PROP_ONLINE,
0342     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0343     POWER_SUPPLY_PROP_CURRENT_NOW,
0344     POWER_SUPPLY_PROP_CHARGE_TYPE,
0345     POWER_SUPPLY_PROP_STATUS,
0346 };
0347 
0348 static const struct power_supply_desc ac_desc = {
0349     .name       = "max8925-ac",
0350     .type       = POWER_SUPPLY_TYPE_MAINS,
0351     .properties = max8925_ac_props,
0352     .num_properties = ARRAY_SIZE(max8925_ac_props),
0353     .get_property   = max8925_ac_get_prop,
0354 };
0355 
0356 static const struct power_supply_desc usb_desc = {
0357     .name       = "max8925-usb",
0358     .type       = POWER_SUPPLY_TYPE_USB,
0359     .properties = max8925_usb_props,
0360     .num_properties = ARRAY_SIZE(max8925_usb_props),
0361     .get_property   = max8925_usb_get_prop,
0362 };
0363 
0364 static const struct power_supply_desc battery_desc = {
0365     .name       = "max8925-battery",
0366     .type       = POWER_SUPPLY_TYPE_BATTERY,
0367     .properties = max8925_battery_props,
0368     .num_properties = ARRAY_SIZE(max8925_battery_props),
0369     .get_property   = max8925_bat_get_prop,
0370 };
0371 
0372 #define REQUEST_IRQ(_irq, _name)                    \
0373 do {                                    \
0374     ret = request_threaded_irq(chip->irq_base + _irq, NULL,     \
0375                     max8925_charger_handler,        \
0376                     IRQF_ONESHOT, _name, info);     \
0377     if (ret)                            \
0378         dev_err(chip->dev, "Failed to request IRQ #%d: %d\n",   \
0379             _irq, ret);                 \
0380 } while (0)
0381 
0382 static int max8925_init_charger(struct max8925_chip *chip,
0383                       struct max8925_power_info *info)
0384 {
0385     int ret;
0386 
0387     REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp");
0388     if (!info->no_insert_detect) {
0389         REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove");
0390         REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert");
0391     }
0392     if (!info->no_temp_support) {
0393         REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range");
0394         REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range");
0395     }
0396     REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high");
0397     REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low");
0398     REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset");
0399     REQUEST_IRQ(MAX8925_IRQ_VCHG_DONE, "charger-done");
0400     REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff");
0401     REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire");
0402 
0403     info->usb_online = 0;
0404     info->bat_online = 0;
0405 
0406     /* check for power - can miss interrupt at boot time */
0407     if (start_measure(info, MEASURE_VCHG) * 2000 > 500000)
0408         info->ac_online = 1;
0409     else
0410         info->ac_online = 0;
0411 
0412     ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
0413     if (ret >= 0) {
0414         /*
0415          * If battery detection is enabled, ID pin of battery is
0416          * connected to MBDET pin of MAX8925. It could be used to
0417          * detect battery presence.
0418          * Otherwise, we have to assume that battery is always on.
0419          */
0420         if (info->batt_detect)
0421             info->bat_online = (ret & MAX8925_CHG_MBDET) ? 0 : 1;
0422         else
0423             info->bat_online = 1;
0424         if (ret & MAX8925_CHG_AC_RANGE_MASK)
0425             info->ac_online = 1;
0426         else
0427             info->ac_online = 0;
0428     }
0429     /* disable charge */
0430     max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7);
0431     /* set charging current in charge topoff mode */
0432     max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 3 << 5,
0433              info->topoff_threshold << 5);
0434     /* set charing current in fast charge mode */
0435     max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 7, info->fast_charge);
0436 
0437     return 0;
0438 }
0439 
0440 static int max8925_deinit_charger(struct max8925_power_info *info)
0441 {
0442     struct max8925_chip *chip = info->chip;
0443     int irq;
0444 
0445     irq = chip->irq_base + MAX8925_IRQ_VCHG_DC_OVP;
0446     for (; irq <= chip->irq_base + MAX8925_IRQ_VCHG_TMR_FAULT; irq++)
0447         free_irq(irq, info);
0448 
0449     return 0;
0450 }
0451 
0452 #ifdef CONFIG_OF
0453 static struct max8925_power_pdata *
0454 max8925_power_dt_init(struct platform_device *pdev)
0455 {
0456     struct device_node *nproot = pdev->dev.parent->of_node;
0457     struct device_node *np;
0458     int batt_detect;
0459     int topoff_threshold;
0460     int fast_charge;
0461     int no_temp_support;
0462     int no_insert_detect;
0463     struct max8925_power_pdata *pdata;
0464 
0465     if (!nproot)
0466         return pdev->dev.platform_data;
0467 
0468     np = of_get_child_by_name(nproot, "charger");
0469     if (!np) {
0470         dev_err(&pdev->dev, "failed to find charger node\n");
0471         return NULL;
0472     }
0473 
0474     pdata = devm_kzalloc(&pdev->dev,
0475             sizeof(struct max8925_power_pdata),
0476             GFP_KERNEL);
0477     if (!pdata)
0478         goto ret;
0479 
0480     of_property_read_u32(np, "topoff-threshold", &topoff_threshold);
0481     of_property_read_u32(np, "batt-detect", &batt_detect);
0482     of_property_read_u32(np, "fast-charge", &fast_charge);
0483     of_property_read_u32(np, "no-insert-detect", &no_insert_detect);
0484     of_property_read_u32(np, "no-temp-support", &no_temp_support);
0485 
0486     pdata->batt_detect = batt_detect;
0487     pdata->fast_charge = fast_charge;
0488     pdata->topoff_threshold = topoff_threshold;
0489     pdata->no_insert_detect = no_insert_detect;
0490     pdata->no_temp_support = no_temp_support;
0491 
0492 ret:
0493     of_node_put(np);
0494     return pdata;
0495 }
0496 #else
0497 static struct max8925_power_pdata *
0498 max8925_power_dt_init(struct platform_device *pdev)
0499 {
0500     return pdev->dev.platform_data;
0501 }
0502 #endif
0503 
0504 static int max8925_power_probe(struct platform_device *pdev)
0505 {
0506     struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
0507     struct power_supply_config psy_cfg = {}; /* Only for ac and usb */
0508     struct max8925_power_pdata *pdata = NULL;
0509     struct max8925_power_info *info;
0510     int ret;
0511 
0512     pdata = max8925_power_dt_init(pdev);
0513     if (!pdata) {
0514         dev_err(&pdev->dev, "platform data isn't assigned to "
0515             "power supply\n");
0516         return -EINVAL;
0517     }
0518 
0519     info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_power_info),
0520                 GFP_KERNEL);
0521     if (!info)
0522         return -ENOMEM;
0523     info->chip = chip;
0524     info->gpm = chip->i2c;
0525     info->adc = chip->adc;
0526     platform_set_drvdata(pdev, info);
0527 
0528     psy_cfg.supplied_to = pdata->supplied_to;
0529     psy_cfg.num_supplicants = pdata->num_supplicants;
0530 
0531     info->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg);
0532     if (IS_ERR(info->ac)) {
0533         ret = PTR_ERR(info->ac);
0534         goto out;
0535     }
0536     info->ac->dev.parent = &pdev->dev;
0537 
0538     info->usb = power_supply_register(&pdev->dev, &usb_desc, &psy_cfg);
0539     if (IS_ERR(info->usb)) {
0540         ret = PTR_ERR(info->usb);
0541         goto out_unregister_ac;
0542     }
0543     info->usb->dev.parent = &pdev->dev;
0544 
0545     info->battery = power_supply_register(&pdev->dev, &battery_desc, NULL);
0546     if (IS_ERR(info->battery)) {
0547         ret = PTR_ERR(info->battery);
0548         goto out_unregister_usb;
0549     }
0550     info->battery->dev.parent = &pdev->dev;
0551 
0552     info->batt_detect = pdata->batt_detect;
0553     info->topoff_threshold = pdata->topoff_threshold;
0554     info->fast_charge = pdata->fast_charge;
0555     info->set_charger = pdata->set_charger;
0556     info->no_temp_support = pdata->no_temp_support;
0557     info->no_insert_detect = pdata->no_insert_detect;
0558 
0559     max8925_init_charger(chip, info);
0560     return 0;
0561 out_unregister_usb:
0562     power_supply_unregister(info->usb);
0563 out_unregister_ac:
0564     power_supply_unregister(info->ac);
0565 out:
0566     return ret;
0567 }
0568 
0569 static int max8925_power_remove(struct platform_device *pdev)
0570 {
0571     struct max8925_power_info *info = platform_get_drvdata(pdev);
0572 
0573     if (info) {
0574         power_supply_unregister(info->ac);
0575         power_supply_unregister(info->usb);
0576         power_supply_unregister(info->battery);
0577         max8925_deinit_charger(info);
0578     }
0579     return 0;
0580 }
0581 
0582 static struct platform_driver max8925_power_driver = {
0583     .probe  = max8925_power_probe,
0584     .remove = max8925_power_remove,
0585     .driver = {
0586         .name   = "max8925-power",
0587     },
0588 };
0589 
0590 module_platform_driver(max8925_power_driver);
0591 
0592 MODULE_LICENSE("GPL");
0593 MODULE_DESCRIPTION("Power supply driver for MAX8925");
0594 MODULE_ALIAS("platform:max8925-power");