summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/pcf50633-charger.c78
1 files changed, 73 insertions, 5 deletions
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
index 48e92c020f4b..21b6e64e7805 100644
--- a/drivers/power/pcf50633-charger.c
+++ b/drivers/power/pcf50633-charger.c
@@ -48,16 +48,21 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
u8 bits;
int charging_start = 1;
u8 mbcs2, chgmod;
+ unsigned int mbcc5;
- if (ma >= 1000)
+ if (ma >= 1000) {
bits = PCF50633_MBCC7_USB_1000mA;
- else if (ma >= 500)
+ ma = 1000;
+ } else if (ma >= 500) {
bits = PCF50633_MBCC7_USB_500mA;
- else if (ma >= 100)
+ ma = 500;
+ } else if (ma >= 100) {
bits = PCF50633_MBCC7_USB_100mA;
- else {
+ ma = 100;
+ } else {
bits = PCF50633_MBCC7_USB_SUSPEND;
charging_start = 0;
+ ma = 0;
}
ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
@@ -67,7 +72,24 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
else
dev_info(pcf->dev, "usb curlim to %d mA\n", ma);
- /* Manual charging start */
+ /*
+ * We limit the charging current to be the USB current limit.
+ * The reason is that on pcf50633, when it enters PMU Standby mode,
+ * which it does when the device goes "off", the USB current limit
+ * reverts to the variant default. In at least one common case, that
+ * default is 500mA. By setting the charging current to be the same
+ * as the USB limit we set here before PMU standby, we enforce it only
+ * using the correct amount of current even when the USB current limit
+ * gets reset to the wrong thing
+ */
+
+ if (mbc->pcf->pdata->charger_reference_current_ma) {
+ mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
+ if (mbcc5 > 255)
+ mbcc5 = 255;
+ pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
+ }
+
mbcs2 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
@@ -157,9 +179,55 @@ static ssize_t set_usblim(struct device *dev,
static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim);
+static ssize_t
+show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
+ u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5);
+ unsigned int ma;
+
+ if (!mbc->pcf->pdata->charger_reference_current_ma)
+ return -ENODEV;
+
+ ma = (mbc->pcf->pdata->charger_reference_current_ma * mbcc5) >> 8;
+
+ return sprintf(buf, "%u\n", ma);
+}
+
+static ssize_t set_chglim(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
+ unsigned long ma;
+ unsigned int mbcc5;
+ int ret;
+
+ if (!mbc->pcf->pdata->charger_reference_current_ma)
+ return -ENODEV;
+
+ ret = strict_strtoul(buf, 10, &ma);
+ if (ret)
+ return -EINVAL;
+
+ mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
+ if (mbcc5 > 255)
+ mbcc5 = 255;
+ pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
+
+ return count;
+}
+
+/*
+ * This attribute allows to change MBC charging limit on the fly
+ * independently of usb current limit. It also gets set automatically every
+ * time usb current limit is changed.
+ */
+static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
+
static struct attribute *pcf50633_mbc_sysfs_entries[] = {
&dev_attr_chgmode.attr,
&dev_attr_usb_curlim.attr,
+ &dev_attr_chg_curlim.attr,
NULL,
};