Hi!

This allows user to disable the green LED, so that it can be used for
other notifications. It also allows him to set lower voltage limits,
and adjust current: lower current and voltage limits will result in
longer battery lifetime.

Currently I'm using

POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,

attributes to control it. Do we have something suitable for LED
control? Are the current/voltage limits ok to use?

Best regards,
                                                                Pavel


diff --git a/drivers/power/supply/cpcap-battery.c 
b/drivers/power/supply/cpcap-battery.c
index 98ba078..839e365 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2017 Tony Lindgren <t...@atomide.com>
  *
- * Some parts of the code based on earlie Motorola mapphone Linux kernel
+ * Some parts of the code based on earlier Motorola mapphone Linux kernel
  * drivers:
  *
  * Copyright (C) 2009-2010 Motorola, Inc.
diff --git a/drivers/power/supply/cpcap-charger.c 
b/drivers/power/supply/cpcap-charger.c
index e4905be..7de07ae 100644
--- a/drivers/power/supply/cpcap-charger.c
+++ b/drivers/power/supply/cpcap-charger.c
@@ -93,6 +93,17 @@
 #define CPCAP_REG_CRM_VCHRG_4V42       CPCAP_REG_CRM_VCHRG(0xe)
 #define CPCAP_REG_CRM_VCHRG_4V44       CPCAP_REG_CRM_VCHRG(0xf)
 
+static int voltage_to_register(int microvolt)
+{
+       switch (microvolt/1000) {
+       case 3800: return CPCAP_REG_CRM_VCHRG_3V80;
+       case 4100: return CPCAP_REG_CRM_VCHRG_4V10;
+       case 4200: return CPCAP_REG_CRM_VCHRG_4V20;
+       case 4350: return CPCAP_REG_CRM_VCHRG_4V35;
+       default: return -EINVAL;
+       }
+}
+
 /*
  * CPCAP_REG_CRM charge currents. These seem to match MC13783UG.pdf
  * values in "Table 8-3. Charge Path Regulator Current Limit
@@ -116,6 +127,18 @@
 #define CPCAP_REG_CRM_ICHRG_1A596      CPCAP_REG_CRM_ICHRG(0xe)
 #define CPCAP_REG_CRM_ICHRG_NO_LIMIT   CPCAP_REG_CRM_ICHRG(0xf)
 
+static int current_to_register(int microamp)
+{
+       switch (microamp/1000) {
+       case 0:    return CPCAP_REG_CRM_ICHRG_0A000;
+       case 70:   return CPCAP_REG_CRM_ICHRG_0A070;
+       case 177:  return CPCAP_REG_CRM_ICHRG_0A177;
+       case 532:  return CPCAP_REG_CRM_ICHRG_0A532;
+       case 1596: return CPCAP_REG_CRM_ICHRG_1A596;
+       default: return -EINVAL;
+       }
+}
+
 enum {
        CPCAP_CHARGER_IIO_BATTDET,
        CPCAP_CHARGER_IIO_VOLTAGE,
@@ -142,6 +165,10 @@ struct cpcap_charger_ddata {
        atomic_t active;
 
        int status;
+
+       int led_enabled;
+       int limit_current;
+       int limit_voltage;
 };
 
 struct cpcap_interrupt_desc {
@@ -163,11 +190,17 @@ struct cpcap_charger_ints_state {
        bool battdetb;
 };
 
+#define POWER_SUPPLY_PROP_INDICATION POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT
+
 static enum power_supply_property cpcap_charger_props[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_ONLINE,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_CURRENT_NOW,
+
+        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+       POWER_SUPPLY_PROP_INDICATION,
 };
 
 static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata)
@@ -229,6 +262,7 @@ static int cpcap_charger_get_property(struct power_supply 
*psy,
                val->intval = ddata->status;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               /* FIXME? Display voltage even when not charging? */
                if (ddata->status == POWER_SUPPLY_STATUS_CHARGING)
                        val->intval = cpcap_charger_get_charge_voltage(ddata) *
                                1000;
@@ -245,6 +279,50 @@ static int cpcap_charger_get_property(struct power_supply 
*psy,
        case POWER_SUPPLY_PROP_ONLINE:
                val->intval = ddata->status == POWER_SUPPLY_STATUS_CHARGING;
                break;
+               
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               // -> charger -- current limit
+               val->intval = ddata->limit_current;
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+               val->intval = ddata->limit_voltage;
+               break;
+       case POWER_SUPPLY_PROP_INDICATION:
+               val->intval = ddata->led_enabled;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cpcap_charger_set_property(struct power_supply *psy,
+                                     enum power_supply_property psp,
+                                     const union power_supply_propval *val)
+{
+       struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               printk("charge current: %d\n", val->intval);
+               if (current_to_register(val->intval) < 0)
+                       return -EINVAL;
+               ddata->limit_current = val->intval;
+               schedule_delayed_work(&ddata->detect_work, 0);
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+               printk("charge voltage: %d\n", val->intval);
+               if (voltage_to_register(val->intval) < 0)
+                       return -EINVAL;
+               ddata->limit_voltage = val->intval;
+               schedule_delayed_work(&ddata->detect_work, 0);
+               break;
+       case POWER_SUPPLY_PROP_INDICATION:
+               printk("hack indication: %d\n", val->intval);
+               ddata->led_enabled = !!val->intval;
+               schedule_delayed_work(&ddata->detect_work, 0);
+               break;
        default:
                return -EINVAL;
        }
@@ -296,7 +374,7 @@ static int cpcap_charger_set_state(struct 
cpcap_charger_ddata *ddata,
        }
 
        error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, 0x3fff,
-                                  CPCAP_REG_CRM_CHRG_LED_EN |
+                                  ddata->led_enabled * 
CPCAP_REG_CRM_CHRG_LED_EN |
                                   trickle_current |
                                   CPCAP_REG_CRM_FET_OVRD |
                                   CPCAP_REG_CRM_FET_CTRL |
@@ -440,16 +518,38 @@ static void cpcap_usb_detect(struct work_struct *work)
                return;
 
        if (cpcap_charger_vbus_valid(ddata) && s.chrgcurr1) {
-               int max_current;
+               int m_voltage, m_current;
+               int reg_current, reg_voltage;
 
                if (cpcap_charger_battery_found(ddata))
-                       max_current = CPCAP_REG_CRM_ICHRG_1A596;
+                       m_current = 1596000;
                else
-                       max_current = CPCAP_REG_CRM_ICHRG_0A532;
+                       m_current = 532000;
+
+               if (m_current > ddata->limit_current)
+                       m_current = ddata->limit_current;
+               
+               m_voltage = 4350000;
+               if (m_voltage > ddata->limit_voltage)
+                       m_voltage = ddata->limit_voltage;
+
+               printk("Charging, %d uV, %d uA\n", m_voltage, m_current);
+               
+               reg_voltage = voltage_to_register(m_voltage);
+               if (reg_voltage < 0) {
+                       dev_err(ddata->dev, "%s impossible voltage\n", 
__func__);
+                       return;
+               }
+                       
+               reg_current = current_to_register(m_current);
+               if (reg_current < 0) {
+                       dev_err(ddata->dev, "%s impossible current\n", 
__func__);
+                       return;
+               }
 
                error = cpcap_charger_set_state(ddata,
-                                               CPCAP_REG_CRM_VCHRG_4V35,
-                                               max_current, 0);
+                                               reg_voltage,
+                                               reg_current, 0);
                if (error)
                        goto out_err;
        } else {
@@ -579,12 +679,27 @@ static int cpcap_charger_init_iio(struct 
cpcap_charger_ddata *ddata)
        return error;
 }
 
+static int cpcap_charger_property_is_writeable(struct power_supply *psy,
+                                                enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+       case POWER_SUPPLY_PROP_INDICATION:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
 static const struct power_supply_desc cpcap_charger_usb_desc = {
        .name           = "usb",
        .type           = POWER_SUPPLY_TYPE_USB,
        .properties     = cpcap_charger_props,
        .num_properties = ARRAY_SIZE(cpcap_charger_props),
        .get_property   = cpcap_charger_get_property,
+       .set_property   = cpcap_charger_set_property,
+       .property_is_writeable = cpcap_charger_property_is_writeable,
 };
 
 #ifdef CONFIG_OF
@@ -619,6 +734,10 @@ static int cpcap_charger_probe(struct platform_device 
*pdev)
        if (!ddata->reg)
                return -ENODEV;
 
+       ddata->limit_current = 1596000;
+       ddata->limit_voltage = 4350000;
+       ddata->led_enabled = 1;
+
        INIT_LIST_HEAD(&ddata->irq_list);
        INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect);
        INIT_DELAYED_WORK(&ddata->vbus_work, cpcap_charger_vbus_work);

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) 
http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

Attachment: signature.asc
Description: Digital signature

Reply via email to