]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/power/supply/axp20x_usb_power.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / drivers / power / supply / axp20x_usb_power.c
index 1bcb02551e028e911c2818d0b2873ebda95bd89c..2397c482656ebb2be64afd550a666ea840fa5fb5 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/power_supply.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/iio/consumer.h>
 
 #define DRVNAME "axp20x-usb-power-supply"
 
@@ -48,7 +49,9 @@ struct axp20x_usb_power {
        struct device_node *np;
        struct regmap *regmap;
        struct power_supply *supply;
-       int axp20x_id;
+       enum axp20x_variants axp20x_id;
+       struct iio_channel *vbus_v;
+       struct iio_channel *vbus_i;
 };
 
 static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
@@ -76,6 +79,20 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
                val->intval = AXP20X_VBUS_VHOLD_uV(v);
                return 0;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
+                       ret = iio_read_channel_processed(power->vbus_v,
+                                                        &val->intval);
+                       if (ret)
+                               return ret;
+
+                       /*
+                        * IIO framework gives mV but Power Supply framework
+                        * gives uV.
+                        */
+                       val->intval *= 1000;
+                       return 0;
+               }
+
                ret = axp20x_read_variable_width(power->regmap,
                                                 AXP20X_VBUS_V_ADC_H, 12);
                if (ret < 0)
@@ -107,6 +124,20 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
                }
                return 0;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
+               if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
+                       ret = iio_read_channel_processed(power->vbus_i,
+                                                        &val->intval);
+                       if (ret)
+                               return ret;
+
+                       /*
+                        * IIO framework gives mA but Power Supply framework
+                        * gives uA.
+                        */
+                       val->intval *= 1000;
+                       return 0;
+               }
+
                ret = axp20x_read_variable_width(power->regmap,
                                                 AXP20X_VBUS_I_ADC_H, 12);
                if (ret < 0)
@@ -269,6 +300,36 @@ static const struct power_supply_desc axp22x_usb_power_desc = {
        .set_property = axp20x_usb_power_set_property,
 };
 
+static int configure_iio_channels(struct platform_device *pdev,
+                                 struct axp20x_usb_power *power)
+{
+       power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
+       if (IS_ERR(power->vbus_v)) {
+               if (PTR_ERR(power->vbus_v) == -ENODEV)
+                       return -EPROBE_DEFER;
+               return PTR_ERR(power->vbus_v);
+       }
+
+       power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i");
+       if (IS_ERR(power->vbus_i)) {
+               if (PTR_ERR(power->vbus_i) == -ENODEV)
+                       return -EPROBE_DEFER;
+               return PTR_ERR(power->vbus_i);
+       }
+
+       return 0;
+}
+
+static int configure_adc_registers(struct axp20x_usb_power *power)
+{
+       /* Enable vbus voltage and current measurement */
+       return regmap_update_bits(power->regmap, AXP20X_ADC_EN1,
+                                 AXP20X_ADC_EN1_VBUS_CURR |
+                                 AXP20X_ADC_EN1_VBUS_VOLT,
+                                 AXP20X_ADC_EN1_VBUS_CURR |
+                                 AXP20X_ADC_EN1_VBUS_VOLT);
+}
+
 static int axp20x_usb_power_probe(struct platform_device *pdev)
 {
        struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
@@ -294,7 +355,8 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
        if (!power)
                return -ENOMEM;
 
-       power->axp20x_id = (int)of_device_get_match_data(&pdev->dev);
+       power->axp20x_id = (enum axp20x_variants)of_device_get_match_data(
+                                                               &pdev->dev);
 
        power->np = pdev->dev.of_node;
        power->regmap = axp20x->regmap;
@@ -307,10 +369,11 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
                if (ret)
                        return ret;
 
-               /* Enable vbus voltage and current measurement */
-               ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1,
-                       AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT,
-                       AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT);
+               if (IS_ENABLED(CONFIG_AXP20X_ADC))
+                       ret = configure_iio_channels(pdev, power);
+               else
+                       ret = configure_adc_registers(power);
+
                if (ret)
                        return ret;