extcon: intel-cht-wc: Add support for registering a power_supply class-device
authorHans de Goede <hdegoede@redhat.com>
Tue, 1 Feb 2022 13:07:05 +0000 (14:07 +0100)
committerSebastian Reichel <sebastian.reichel@collabora.com>
Tue, 1 Feb 2022 13:55:12 +0000 (14:55 +0100)
The bq25890 used on the Yogabook YB1-X90 / -X91 models relies on
the extcon-driver's BC-1.2 charger detection, and the bq25890 driver
expect this info to be  available through a parent power_supply
class-device which models the detected charger (idem to how the Type-C
TCPM code registers a power_supply classdev for the connected charger).

Add support for registering the power_supply class-device expected
by this setup.

Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
drivers/extcon/extcon-intel-cht-wc.c

index a828ca89ca7f140e2d7bbf0b0988ee89138aa343..cf74acb92fe32b06712e48ff9ecd66766e39d36c 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
+#include <linux/power_supply.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
@@ -106,6 +107,8 @@ struct cht_wc_extcon_data {
        struct extcon_dev *edev;
        struct usb_role_switch *role_sw;
        struct regulator *vbus_boost;
+       struct power_supply *psy;
+       enum power_supply_usb_type usb_type;
        unsigned int previous_cable;
        bool usb_host;
        bool vbus_boost_enabled;
@@ -170,18 +173,23 @@ static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
                dev_warn(ext->dev,
                        "Unhandled charger type %d, defaulting to SDP\n",
                         ret);
+               ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP;
                return EXTCON_CHG_USB_SDP;
        case CHT_WC_USBSRC_TYPE_SDP:
        case CHT_WC_USBSRC_TYPE_FLOATING:
        case CHT_WC_USBSRC_TYPE_OTHER:
+               ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP;
                return EXTCON_CHG_USB_SDP;
        case CHT_WC_USBSRC_TYPE_CDP:
+               ext->usb_type = POWER_SUPPLY_USB_TYPE_CDP;
                return EXTCON_CHG_USB_CDP;
        case CHT_WC_USBSRC_TYPE_DCP:
        case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
        case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
+               ext->usb_type = POWER_SUPPLY_USB_TYPE_DCP;
                return EXTCON_CHG_USB_DCP;
        case CHT_WC_USBSRC_TYPE_ACA:
+               ext->usb_type = POWER_SUPPLY_USB_TYPE_ACA;
                return EXTCON_CHG_USB_ACA;
        }
 }
@@ -266,6 +274,8 @@ static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext)
        bool ignore_get_charger_errors = ext->usb_host;
        enum usb_role role;
 
+       ext->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+
        ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
        if (ret) {
                dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
@@ -320,6 +330,9 @@ set_state:
        ret = usb_role_switch_set_role(ext->role_sw, role);
        if (ret)
                dev_err(ext->dev, "Error setting USB-role: %d\n", ret);
+
+       if (ext->psy)
+               power_supply_changed(ext->psy);
 }
 
 static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
@@ -420,6 +433,59 @@ static int cht_wc_extcon_get_role_sw_and_regulator(struct cht_wc_extcon_data *ex
        return 0;
 }
 
+static int cht_wc_extcon_psy_get_prop(struct power_supply *psy,
+                                     enum power_supply_property psp,
+                                     union power_supply_propval *val)
+{
+       struct cht_wc_extcon_data *ext = power_supply_get_drvdata(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_USB_TYPE:
+               val->intval = ext->usb_type;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = ext->usb_type ? 1 : 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const enum power_supply_usb_type cht_wc_extcon_psy_usb_types[] = {
+       POWER_SUPPLY_USB_TYPE_SDP,
+       POWER_SUPPLY_USB_TYPE_CDP,
+       POWER_SUPPLY_USB_TYPE_DCP,
+       POWER_SUPPLY_USB_TYPE_ACA,
+       POWER_SUPPLY_USB_TYPE_UNKNOWN,
+};
+
+static const enum power_supply_property cht_wc_extcon_psy_props[] = {
+       POWER_SUPPLY_PROP_USB_TYPE,
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+static const struct power_supply_desc cht_wc_extcon_psy_desc = {
+       .name = "cht_wcove_pwrsrc",
+       .type = POWER_SUPPLY_TYPE_USB,
+       .usb_types = cht_wc_extcon_psy_usb_types,
+       .num_usb_types = ARRAY_SIZE(cht_wc_extcon_psy_usb_types),
+       .properties = cht_wc_extcon_psy_props,
+       .num_properties = ARRAY_SIZE(cht_wc_extcon_psy_props),
+       .get_property = cht_wc_extcon_psy_get_prop,
+};
+
+static int cht_wc_extcon_register_psy(struct cht_wc_extcon_data *ext)
+{
+       struct power_supply_config psy_cfg = { .drv_data = ext };
+
+       ext->psy = devm_power_supply_register(ext->dev,
+                                             &cht_wc_extcon_psy_desc,
+                                             &psy_cfg);
+       return PTR_ERR_OR_ZERO(ext->psy);
+}
+
 static int cht_wc_extcon_probe(struct platform_device *pdev)
 {
        struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
@@ -463,6 +529,21 @@ static int cht_wc_extcon_probe(struct platform_device *pdev)
                cht_wc_extcon_set_5v_boost(ext, false);
                break;
        case INTEL_CHT_WC_LENOVO_YOGABOOK1:
+               /* Do this first, as it may very well return -EPROBE_DEFER. */
+               ret = cht_wc_extcon_get_role_sw_and_regulator(ext);
+               if (ret)
+                       return ret;
+               /*
+                * The bq25890 used here relies on this driver's BC-1.2 charger
+                * detection, and the bq25890 driver expect this info to be
+                * available through a parent power_supply class device which
+                * models the detected charger (idem to how the Type-C TCPM code
+                * registers a power_supply classdev for the connected charger).
+                */
+               ret = cht_wc_extcon_register_psy(ext);
+               if (ret)
+                       return ret;
+               break;
        case INTEL_CHT_WC_XIAOMI_MIPAD2:
                ret = cht_wc_extcon_get_role_sw_and_regulator(ext);
                if (ret)