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.