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 <[email protected]>
---
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 [email protected].
For more options, visit https://groups.google.com/d/optout.