Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* NXP PCF50633 Main Battery Charger Driver
0003  *
0004  * (C) 2006-2008 by Openmoko, Inc.
0005  * Author: Balaji Rao <balajirrao@openmoko.org>
0006  * All rights reserved.
0007  *
0008  * Broken down from monstrous PCF50633 driver mainly by
0009  * Harald Welte, Andy Green and Werner Almesberger
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/slab.h>
0015 #include <linux/init.h>
0016 #include <linux/types.h>
0017 #include <linux/device.h>
0018 #include <linux/sysfs.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/power_supply.h>
0021 
0022 #include <linux/mfd/pcf50633/core.h>
0023 #include <linux/mfd/pcf50633/mbc.h>
0024 
0025 struct pcf50633_mbc {
0026     struct pcf50633 *pcf;
0027 
0028     int adapter_online;
0029     int usb_online;
0030 
0031     struct power_supply *usb;
0032     struct power_supply *adapter;
0033     struct power_supply *ac;
0034 };
0035 
0036 int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
0037 {
0038     struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
0039     int ret = 0;
0040     u8 bits;
0041     u8 mbcs2, chgmod;
0042     unsigned int mbcc5;
0043 
0044     if (ma >= 1000) {
0045         bits = PCF50633_MBCC7_USB_1000mA;
0046         ma = 1000;
0047     } else if (ma >= 500) {
0048         bits = PCF50633_MBCC7_USB_500mA;
0049         ma = 500;
0050     } else if (ma >= 100) {
0051         bits = PCF50633_MBCC7_USB_100mA;
0052         ma = 100;
0053     } else {
0054         bits = PCF50633_MBCC7_USB_SUSPEND;
0055         ma = 0;
0056     }
0057 
0058     ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
0059                     PCF50633_MBCC7_USB_MASK, bits);
0060     if (ret)
0061         dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
0062     else
0063         dev_info(pcf->dev, "usb curlim to %d mA\n", ma);
0064 
0065     /*
0066      * We limit the charging current to be the USB current limit.
0067      * The reason is that on pcf50633, when it enters PMU Standby mode,
0068      * which it does when the device goes "off", the USB current limit
0069      * reverts to the variant default.  In at least one common case, that
0070      * default is 500mA.  By setting the charging current to be the same
0071      * as the USB limit we set here before PMU standby, we enforce it only
0072      * using the correct amount of current even when the USB current limit
0073      * gets reset to the wrong thing
0074      */
0075 
0076     if (mbc->pcf->pdata->charger_reference_current_ma) {
0077         mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
0078         if (mbcc5 > 255)
0079             mbcc5 = 255;
0080         pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
0081     }
0082 
0083     mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
0084     chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
0085 
0086     /* If chgmod == BATFULL, setting chgena has no effect.
0087      * Datasheet says we need to set resume instead but when autoresume is
0088      * used resume doesn't work. Clear and set chgena instead.
0089      */
0090     if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
0091         pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
0092                 PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
0093     else {
0094         pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1,
0095                 PCF50633_MBCC1_CHGENA);
0096         pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
0097                 PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
0098     }
0099 
0100     power_supply_changed(mbc->usb);
0101 
0102     return ret;
0103 }
0104 EXPORT_SYMBOL_GPL(pcf50633_mbc_usb_curlim_set);
0105 
0106 int pcf50633_mbc_get_status(struct pcf50633 *pcf)
0107 {
0108     struct pcf50633_mbc *mbc  = platform_get_drvdata(pcf->mbc_pdev);
0109     int status = 0;
0110     u8 chgmod;
0111 
0112     if (!mbc)
0113         return 0;
0114 
0115     chgmod = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2)
0116         & PCF50633_MBCS2_MBC_MASK;
0117 
0118     if (mbc->usb_online)
0119         status |= PCF50633_MBC_USB_ONLINE;
0120     if (chgmod == PCF50633_MBCS2_MBC_USB_PRE ||
0121         chgmod == PCF50633_MBCS2_MBC_USB_PRE_WAIT ||
0122         chgmod == PCF50633_MBCS2_MBC_USB_FAST ||
0123         chgmod == PCF50633_MBCS2_MBC_USB_FAST_WAIT)
0124         status |= PCF50633_MBC_USB_ACTIVE;
0125     if (mbc->adapter_online)
0126         status |= PCF50633_MBC_ADAPTER_ONLINE;
0127     if (chgmod == PCF50633_MBCS2_MBC_ADP_PRE ||
0128         chgmod == PCF50633_MBCS2_MBC_ADP_PRE_WAIT ||
0129         chgmod == PCF50633_MBCS2_MBC_ADP_FAST ||
0130         chgmod == PCF50633_MBCS2_MBC_ADP_FAST_WAIT)
0131         status |= PCF50633_MBC_ADAPTER_ACTIVE;
0132 
0133     return status;
0134 }
0135 EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status);
0136 
0137 int pcf50633_mbc_get_usb_online_status(struct pcf50633 *pcf)
0138 {
0139     struct pcf50633_mbc *mbc  = platform_get_drvdata(pcf->mbc_pdev);
0140 
0141     if (!mbc)
0142         return 0;
0143 
0144     return mbc->usb_online;
0145 }
0146 EXPORT_SYMBOL_GPL(pcf50633_mbc_get_usb_online_status);
0147 
0148 static ssize_t
0149 show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
0150 {
0151     struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0152 
0153     u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
0154     u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
0155 
0156     return sprintf(buf, "%d\n", chgmod);
0157 }
0158 static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL);
0159 
0160 static ssize_t
0161 show_usblim(struct device *dev, struct device_attribute *attr, char *buf)
0162 {
0163     struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0164     u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
0165                         PCF50633_MBCC7_USB_MASK;
0166     unsigned int ma;
0167 
0168     if (usblim == PCF50633_MBCC7_USB_1000mA)
0169         ma = 1000;
0170     else if (usblim == PCF50633_MBCC7_USB_500mA)
0171         ma = 500;
0172     else if (usblim == PCF50633_MBCC7_USB_100mA)
0173         ma = 100;
0174     else
0175         ma = 0;
0176 
0177     return sprintf(buf, "%u\n", ma);
0178 }
0179 
0180 static ssize_t set_usblim(struct device *dev,
0181         struct device_attribute *attr, const char *buf, size_t count)
0182 {
0183     struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0184     unsigned long ma;
0185     int ret;
0186 
0187     ret = kstrtoul(buf, 10, &ma);
0188     if (ret)
0189         return ret;
0190 
0191     pcf50633_mbc_usb_curlim_set(mbc->pcf, ma);
0192 
0193     return count;
0194 }
0195 
0196 static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim);
0197 
0198 static ssize_t
0199 show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
0200 {
0201     struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0202     u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5);
0203     unsigned int ma;
0204 
0205     if (!mbc->pcf->pdata->charger_reference_current_ma)
0206         return -ENODEV;
0207 
0208     ma = (mbc->pcf->pdata->charger_reference_current_ma *  mbcc5) >> 8;
0209 
0210     return sprintf(buf, "%u\n", ma);
0211 }
0212 
0213 static ssize_t set_chglim(struct device *dev,
0214         struct device_attribute *attr, const char *buf, size_t count)
0215 {
0216     struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0217     unsigned long ma;
0218     unsigned int mbcc5;
0219     int ret;
0220 
0221     if (!mbc->pcf->pdata->charger_reference_current_ma)
0222         return -ENODEV;
0223 
0224     ret = kstrtoul(buf, 10, &ma);
0225     if (ret)
0226         return ret;
0227 
0228     mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
0229     if (mbcc5 > 255)
0230         mbcc5 = 255;
0231     pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
0232 
0233     return count;
0234 }
0235 
0236 /*
0237  * This attribute allows to change MBC charging limit on the fly
0238  * independently of usb current limit. It also gets set automatically every
0239  * time usb current limit is changed.
0240  */
0241 static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
0242 
0243 static struct attribute *pcf50633_mbc_sysfs_attrs[] = {
0244     &dev_attr_chgmode.attr,
0245     &dev_attr_usb_curlim.attr,
0246     &dev_attr_chg_curlim.attr,
0247     NULL,
0248 };
0249 
0250 ATTRIBUTE_GROUPS(pcf50633_mbc_sysfs);
0251 
0252 static void
0253 pcf50633_mbc_irq_handler(int irq, void *data)
0254 {
0255     struct pcf50633_mbc *mbc = data;
0256 
0257     /* USB */
0258     if (irq == PCF50633_IRQ_USBINS) {
0259         mbc->usb_online = 1;
0260     } else if (irq == PCF50633_IRQ_USBREM) {
0261         mbc->usb_online = 0;
0262         pcf50633_mbc_usb_curlim_set(mbc->pcf, 0);
0263     }
0264 
0265     /* Adapter */
0266     if (irq == PCF50633_IRQ_ADPINS)
0267         mbc->adapter_online = 1;
0268     else if (irq == PCF50633_IRQ_ADPREM)
0269         mbc->adapter_online = 0;
0270 
0271     power_supply_changed(mbc->ac);
0272     power_supply_changed(mbc->usb);
0273     power_supply_changed(mbc->adapter);
0274 
0275     if (mbc->pcf->pdata->mbc_event_callback)
0276         mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq);
0277 }
0278 
0279 static int adapter_get_property(struct power_supply *psy,
0280             enum power_supply_property psp,
0281             union power_supply_propval *val)
0282 {
0283     struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
0284     int ret = 0;
0285 
0286     switch (psp) {
0287     case POWER_SUPPLY_PROP_ONLINE:
0288         val->intval =  mbc->adapter_online;
0289         break;
0290     default:
0291         ret = -EINVAL;
0292         break;
0293     }
0294     return ret;
0295 }
0296 
0297 static int usb_get_property(struct power_supply *psy,
0298             enum power_supply_property psp,
0299             union power_supply_propval *val)
0300 {
0301     struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
0302     int ret = 0;
0303     u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
0304                         PCF50633_MBCC7_USB_MASK;
0305 
0306     switch (psp) {
0307     case POWER_SUPPLY_PROP_ONLINE:
0308         val->intval = mbc->usb_online &&
0309                 (usblim <= PCF50633_MBCC7_USB_500mA);
0310         break;
0311     default:
0312         ret = -EINVAL;
0313         break;
0314     }
0315     return ret;
0316 }
0317 
0318 static int ac_get_property(struct power_supply *psy,
0319             enum power_supply_property psp,
0320             union power_supply_propval *val)
0321 {
0322     struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
0323     int ret = 0;
0324     u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
0325                         PCF50633_MBCC7_USB_MASK;
0326 
0327     switch (psp) {
0328     case POWER_SUPPLY_PROP_ONLINE:
0329         val->intval = mbc->usb_online &&
0330                 (usblim == PCF50633_MBCC7_USB_1000mA);
0331         break;
0332     default:
0333         ret = -EINVAL;
0334         break;
0335     }
0336     return ret;
0337 }
0338 
0339 static enum power_supply_property power_props[] = {
0340     POWER_SUPPLY_PROP_ONLINE,
0341 };
0342 
0343 static const u8 mbc_irq_handlers[] = {
0344     PCF50633_IRQ_ADPINS,
0345     PCF50633_IRQ_ADPREM,
0346     PCF50633_IRQ_USBINS,
0347     PCF50633_IRQ_USBREM,
0348     PCF50633_IRQ_BATFULL,
0349     PCF50633_IRQ_CHGHALT,
0350     PCF50633_IRQ_THLIMON,
0351     PCF50633_IRQ_THLIMOFF,
0352     PCF50633_IRQ_USBLIMON,
0353     PCF50633_IRQ_USBLIMOFF,
0354     PCF50633_IRQ_LOWSYS,
0355     PCF50633_IRQ_LOWBAT,
0356 };
0357 
0358 static const struct power_supply_desc pcf50633_mbc_adapter_desc = {
0359     .name       = "adapter",
0360     .type       = POWER_SUPPLY_TYPE_MAINS,
0361     .properties = power_props,
0362     .num_properties = ARRAY_SIZE(power_props),
0363     .get_property   = &adapter_get_property,
0364 };
0365 
0366 static const struct power_supply_desc pcf50633_mbc_usb_desc = {
0367     .name       = "usb",
0368     .type       = POWER_SUPPLY_TYPE_USB,
0369     .properties = power_props,
0370     .num_properties = ARRAY_SIZE(power_props),
0371     .get_property   = usb_get_property,
0372 };
0373 
0374 static const struct power_supply_desc pcf50633_mbc_ac_desc = {
0375     .name       = "ac",
0376     .type       = POWER_SUPPLY_TYPE_MAINS,
0377     .properties = power_props,
0378     .num_properties = ARRAY_SIZE(power_props),
0379     .get_property   = ac_get_property,
0380 };
0381 
0382 static int pcf50633_mbc_probe(struct platform_device *pdev)
0383 {
0384     struct power_supply_config psy_cfg = {};
0385     struct power_supply_config usb_psy_cfg;
0386     struct pcf50633_mbc *mbc;
0387     int i;
0388     u8 mbcs1;
0389 
0390     mbc = devm_kzalloc(&pdev->dev, sizeof(*mbc), GFP_KERNEL);
0391     if (!mbc)
0392         return -ENOMEM;
0393 
0394     platform_set_drvdata(pdev, mbc);
0395     mbc->pcf = dev_to_pcf50633(pdev->dev.parent);
0396 
0397     /* Set up IRQ handlers */
0398     for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
0399         pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i],
0400                     pcf50633_mbc_irq_handler, mbc);
0401 
0402     psy_cfg.supplied_to     = mbc->pcf->pdata->batteries;
0403     psy_cfg.num_supplicants     = mbc->pcf->pdata->num_batteries;
0404     psy_cfg.drv_data        = mbc;
0405 
0406     /* Create power supplies */
0407     mbc->adapter = power_supply_register(&pdev->dev,
0408                          &pcf50633_mbc_adapter_desc,
0409                          &psy_cfg);
0410     if (IS_ERR(mbc->adapter)) {
0411         dev_err(mbc->pcf->dev, "failed to register adapter\n");
0412         return PTR_ERR(mbc->adapter);
0413     }
0414 
0415     usb_psy_cfg = psy_cfg;
0416     usb_psy_cfg.attr_grp = pcf50633_mbc_sysfs_groups;
0417 
0418     mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc,
0419                      &usb_psy_cfg);
0420     if (IS_ERR(mbc->usb)) {
0421         dev_err(mbc->pcf->dev, "failed to register usb\n");
0422         power_supply_unregister(mbc->adapter);
0423         return PTR_ERR(mbc->usb);
0424     }
0425 
0426     mbc->ac = power_supply_register(&pdev->dev, &pcf50633_mbc_ac_desc,
0427                     &psy_cfg);
0428     if (IS_ERR(mbc->ac)) {
0429         dev_err(mbc->pcf->dev, "failed to register ac\n");
0430         power_supply_unregister(mbc->adapter);
0431         power_supply_unregister(mbc->usb);
0432         return PTR_ERR(mbc->ac);
0433     }
0434 
0435     mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
0436     if (mbcs1 & PCF50633_MBCS1_USBPRES)
0437         pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
0438     if (mbcs1 & PCF50633_MBCS1_ADAPTPRES)
0439         pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc);
0440 
0441     return 0;
0442 }
0443 
0444 static int pcf50633_mbc_remove(struct platform_device *pdev)
0445 {
0446     struct pcf50633_mbc *mbc = platform_get_drvdata(pdev);
0447     int i;
0448 
0449     /* Remove IRQ handlers */
0450     for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
0451         pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
0452 
0453     power_supply_unregister(mbc->usb);
0454     power_supply_unregister(mbc->adapter);
0455     power_supply_unregister(mbc->ac);
0456 
0457     return 0;
0458 }
0459 
0460 static struct platform_driver pcf50633_mbc_driver = {
0461     .driver = {
0462         .name = "pcf50633-mbc",
0463     },
0464     .probe = pcf50633_mbc_probe,
0465     .remove = pcf50633_mbc_remove,
0466 };
0467 
0468 module_platform_driver(pcf50633_mbc_driver);
0469 
0470 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
0471 MODULE_DESCRIPTION("PCF50633 mbc driver");
0472 MODULE_LICENSE("GPL");
0473 MODULE_ALIAS("platform:pcf50633-mbc");