The AXP20X chips can protect the VBUS(USB) input path, when in use, by 
disconnecting it when some configurable conditions are met:
    the VBUS input voltage is lower than the configured value
    the VBUS input current is higher than the configured value

This patch creates 3 device tree parameters that configure the VBUS-IPSOUT 
channel management register at driver start-up.
The added parameters are:
    vhold-enable:
        - missing : the original register value is not altered
        - 0 : the VBUS protection feature is disabled
        - 1 : the VBUS protection feature is enabled
    vhold-set:
        - missing : the original register value is not altered
        - 4000000 : vhold limit set to 4.000 volts
        - 4100000 : vhold limit set to 4.100 volts
        ...
        - 4700000 : vhold limit set to 4.700 volts
        - any other value : the original register value is not altered
    ibus-limit:
        - missing : the original register value is not altered
        - 100000 : limit set to 100mA
        - 500000 : limit set to 500mA
        - 900000 : limit set to 900mA
        - any other value : current limit check disabled

Signed-off-by: Ene Alexandru <ene.alexan...@gmail.com>
---
 drivers/power/axp20x_usb_power.c |  124 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/drivers/power/axp20x_usb_power.c b/drivers/power/axp20x_usb_power.c
index 421a90b..1bd8fce 100644
--- a/drivers/power/axp20x_usb_power.c
+++ b/drivers/power/axp20x_usb_power.c
@@ -41,6 +41,27 @@
 
 #define AXP20X_VBUS_MON_VBUS_VALID     BIT(3)
 
+/* bit defines for REG 30H: VBUS-IPSOUT Power Path Management */
+/* VBUS VHOLD voltage limiting control  */
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD          BIT(6)
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD_ENA      BIT(6)
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD_DIS      BIT(0)
+/* VHOLD Set voltage */
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD_SET_MASK (BIT(5)|BIT(4)|BIT(3))
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD_SET_SHIFT (3)
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD_MIN_VAL   (4000000)
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD_MAX_VAL   (4700000)
+#define AXP20X_VBUS_IPSOUT_MGMT_VHOLD_DIV_VAL   (100000)
+/* VBUS current-limit selection */
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_MASK              (BIT(1) | BIT(0))
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_100MA             (100000)
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_100MA_BITS        (BIT(1))
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_500MA             (500000)
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_500MA_BITS        (BIT(0))
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_900MA             (900000)
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_900MA_BITS        (0)
+#define AXP20X_VBUS_IPSOUT_MGMT_IBUS_UNLIM_BITS        (BIT(1) | BIT(0))
+
 struct axp20x_usb_power {
        struct regmap *regmap;
        struct power_supply *supply;
@@ -164,6 +185,104 @@ static const struct power_supply_desc 
axp20x_usb_power_desc = {
        .get_property = axp20x_usb_power_get_property,
 };
 
+static int axp20x_usb_power_read_params(const struct device_node *node,
+               struct axp20x_usb_power *power, struct platform_device *pdev)
+{
+       const u32 *prop;
+       u32 tempPropVal;
+       u32 tempRegVal;
+       int ret;
+
+       prop = of_get_property(node, "vhold-enable", NULL);
+       if (prop) {
+               /* either 1 or 0 */
+               dev_dbg(&pdev->dev, "vhold-enable=%d",
+                       !!(*prop));
+               if (!!(*prop)) {
+                       ret = regmap_update_bits(power->regmap,
+                                       AXP20X_VBUS_IPSOUT_MGMT,
+                                       AXP20X_VBUS_IPSOUT_MGMT_VHOLD,
+                                       AXP20X_VBUS_IPSOUT_MGMT_VHOLD_ENA);
+               } else {
+                       ret = regmap_update_bits(power->regmap,
+                                       AXP20X_VBUS_IPSOUT_MGMT,
+                                       AXP20X_VBUS_IPSOUT_MGMT_VHOLD,
+                                       AXP20X_VBUS_IPSOUT_MGMT_VHOLD_DIS);
+               }
+               if (ret)
+                       return ret;
+       } else {
+               dev_dbg(&pdev->dev, "no vhold-enable property found");
+       }
+
+       prop = of_get_property(node, "vhold-set", NULL);
+       if (prop) {
+               /* shift the bytes arround */
+               tempPropVal = ((*prop)>>24) & 0x000000FF;
+               tempPropVal |= ((*prop)>>8) & 0x0000FF00;
+               tempPropVal |= ((*prop)<<8) & 0x00FF0000;
+               tempPropVal |= ((*prop)<<24) & 0xFF000000;
+
+               /* prepare register value */
+               /* check that */
+               if ((tempPropVal >= AXP20X_VBUS_IPSOUT_MGMT_VHOLD_MIN_VAL) &&
+                       (tempPropVal <= AXP20X_VBUS_IPSOUT_MGMT_VHOLD_MAX_VAL)) 
{
+                       tempRegVal = tempPropVal - 
AXP20X_VBUS_IPSOUT_MGMT_VHOLD_MIN_VAL;
+                       tempRegVal = tempRegVal / 
AXP20X_VBUS_IPSOUT_MGMT_VHOLD_DIV_VAL;
+                       dev_dbg(&pdev->dev, "vhold-set=%duV",
+                               AXP20X_VBUS_IPSOUT_MGMT_VHOLD_MIN_VAL+
+                               
(tempRegVal*AXP20X_VBUS_IPSOUT_MGMT_VHOLD_DIV_VAL));
+                       ret = regmap_update_bits(power->regmap,
+                               AXP20X_VBUS_IPSOUT_MGMT,
+                               AXP20X_VBUS_IPSOUT_MGMT_VHOLD_SET_MASK,
+                               (tempRegVal) << 
AXP20X_VBUS_IPSOUT_MGMT_VHOLD_SET_SHIFT);
+                       if (ret)
+                               return ret;
+               } else {
+                       dev_dbg(&pdev->dev, "vhold-set %d out of range", 
tempPropVal);
+               }
+       } else {
+               dev_dbg(&pdev->dev, "no vhold-set property found");
+       }
+
+       prop = of_get_property(node, "ibus-limit", NULL);
+       if (prop) {
+               /* shift the bytes arround */
+               tempPropVal = ((*prop)>>24) & 0x000000FF;
+               tempPropVal |= ((*prop)>>8) & 0x0000FF00;
+               tempPropVal |= ((*prop)<<8) & 0x00FF0000;
+               tempPropVal |= ((*prop)<<24) & 0xFF000000;
+
+               switch (tempPropVal) {
+               case AXP20X_VBUS_IPSOUT_MGMT_IBUS_100MA:
+                       dev_dbg(&pdev->dev, "ibus-limit=100000uA");
+                       tempRegVal = AXP20X_VBUS_IPSOUT_MGMT_IBUS_100MA_BITS;
+                       break;
+               case AXP20X_VBUS_IPSOUT_MGMT_IBUS_500MA:
+                       dev_dbg(&pdev->dev, "ibus-limit=500000uA");
+                       tempRegVal = AXP20X_VBUS_IPSOUT_MGMT_IBUS_500MA_BITS;
+                       break;
+               case AXP20X_VBUS_IPSOUT_MGMT_IBUS_900MA:
+                       dev_dbg(&pdev->dev, "ibus-limit=900000uA");
+                       tempRegVal = AXP20X_VBUS_IPSOUT_MGMT_IBUS_900MA_BITS;
+                       break;
+               default:
+                       dev_dbg(&pdev->dev, "ibus-limit=UNLIMITED");
+                       tempRegVal = AXP20X_VBUS_IPSOUT_MGMT_IBUS_UNLIM_BITS;
+                       break;
+               }
+               ret = regmap_update_bits(power->regmap, AXP20X_VBUS_IPSOUT_MGMT,
+                                       AXP20X_VBUS_IPSOUT_MGMT_IBUS_MASK,
+                                       tempRegVal);
+               if (ret)
+                       return ret;
+       } else {
+               dev_dbg(&pdev->dev, "no ibus-limit property found");
+       }
+
+       return 0;
+}
+
 static int axp20x_usb_power_probe(struct platform_device *pdev)
 {
        struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
@@ -172,6 +291,7 @@ static int axp20x_usb_power_probe(struct platform_device 
*pdev)
        static const char * const irq_names[] = { "VBUS_PLUGIN",
                "VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID" };
        int i, irq, ret;
+       struct device_node *node;
 
        if (!of_device_is_available(pdev->dev.of_node))
                return -ENODEV;
@@ -208,6 +328,10 @@ static int axp20x_usb_power_probe(struct platform_device 
*pdev)
        if (IS_ERR(power->supply))
                return PTR_ERR(power->supply);
 
+       /* read DT configurations parameters, if available */
+       for_each_compatible_node(node, NULL, "x-powers,axp202-usb-power-supply")
+                       axp20x_usb_power_read_params(node, power, pdev);
+
        /* Request irqs after registering, as irqs may trigger immediately */
        for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
                irq = platform_get_irq_byname(pdev, irq_names[i]);
-- 
1.7.10.4

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to