Re: [PATCH] power: supply: axp288_charger: Add special handling for HP Pavilion x2 10

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Sun, Feb 23, 2020 at 04:32:08PM +0100, Hans de Goede wrote:
> Some HP Pavilion x2 10 models use an AXP288 for charging and fuel-gauge.
> We use a native power_supply / PMIC driver in this case, because on most
> models with an AXP288 the ACPI AC / Battery code is either completely
> missing or relies on custom / proprietary ACPI OpRegions which Linux
> does not implement.
> 
> The native drivers mostly work fine, but there are 2 problems:
> 
> 1. These model uses a Type-C connector for charging which the AXP288 does
> not support. As long as a Type-A charger (which uses the USB data pins for
> charger type detection) is used everything is fine. But if a Type-C
> charger is used (such as the charger shipped with the device) then the
> charger is not recognized.
> 
> So we end up slowly discharging the device even though a charger is
> connected, because we are limiting the current from the charger to 500mA.
> To make things worse this happens with the device's official charger.
> 
> Looking at the ACPI tables HP has "solved" the problem of the AXP288 not
> being able to recognize Type-C chargers by simply always programming the
> input-current-limit at 3000mA and relying on a Vhold setting of 4.7V
> (normally 4.4V) to limit the current intake if the charger cannot handle
> this.
> 
> 2. If no charger is connected when the machine boots then it boots with the
> vbus-path disabled. On other devices this is done when a 5V boost converter
> is active to avoid the PMIC trying to charge from the 5V boost output.
> This is done when an OTG host cable is inserted and the ID pin on the
> micro-B receptacle is pulled low, the ID pin has an ACPI event handler
> associated with it which re-enables the vbus-path when the ID pin is pulled
> high when the OTG cable is removed. The Type-C connector has no ID pin,
> there is no ID pin handler and there appears to be no 5V boost converter,
> so we end up not charging because the vbus-path is disabled, until we
> unplug the charger which automatically clears the vbus-path disable bit and
> then on the second plug-in of the adapter we start charging.
> 
> The HP Pavilion x2 10 models with an AXP288 do have mostly working ACPI
> AC / Battery code which does not rely on custom / proprietary ACPI
> OpRegions. So one possible solution would be to blacklist the AXP288
> native power_supply drivers and add the HP Pavilion x2 10 with AXP288
> DMI ids to the list of devices which should use the ACPI AC / Battery
> code even though they have an AXP288 PMIC. This would require changes to
> 4 files: drivers/acpi/ac.c, drivers/power/supply/axp288_charger.c,
> drivers/acpi/battery.c and drivers/power/supply/axp288_fuel_gauge.c.
> 
> Beside needing adding the same DMI matches to 4 different files, this
> approach also triggers problem 2. from above, but then when suspended,
> during suspend the machine will not wakeup because the vbus path is
> disabled by the AML code when not charging, so the Vbus low-to-high
> IRQ is not triggered, the CPU never wakes up and the device does not
> charge even though the user likely things it is charging, esp. since
> the charge status LED is directly coupled to an adapter being plugged
> in and does not reflect actual charging.
> 
> This could be worked by enabling vbus-path explicitly from say the
> axp288_charger driver's suspend handler.
> 
> So neither situation is ideal, in both cased we need to explicitly enable
> the vbus-path to work around different variants of problem 2 above, this
> requires a quirk in the axp288_charger code.
> 
> If we go the route of using the ACPI AC / Battery drivers then we need
> modifications to 3 other drivers; and we need to partially disable the
> axp288_charger code, while at the same time keeping it around to enable
> vbus-path on suspend.
> 
> OTOH we can copy the hardcoding of 3A input-current-limit (we never touch
> Vhold, so that would stay at 4.7V) to the axp288_charger code, which needs
> changes regardless, then we concentrate all special handling of this
> interesting device model in the axp288_charger code. That is what this
> commit does.
> 
> Cc: stable@xxxxxxxxxxxxxxx
> BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1791098
> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx>
> ---

Thanks for the nice explanations in the commit message and the
comment in the code :) I queued the patch to power-supply's
for-next branch wondering if there is any sane system containing
an axp288.

-- Sebastian

>  drivers/power/supply/axp288_charger.c | 57 ++++++++++++++++++++++++++-
>  1 file changed, 56 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c
> index 1bbba6bba673..cf4c67b2d235 100644
> --- a/drivers/power/supply/axp288_charger.c
> +++ b/drivers/power/supply/axp288_charger.c
> @@ -21,6 +21,7 @@
>  #include <linux/property.h>
>  #include <linux/mfd/axp20x.h>
>  #include <linux/extcon.h>
> +#include <linux/dmi.h>
>  
>  #define PS_STAT_VBUS_TRIGGER		BIT(0)
>  #define PS_STAT_BAT_CHRG_DIR		BIT(2)
> @@ -545,6 +546,49 @@ static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
>  	return IRQ_HANDLED;
>  }
>  
> +/*
> + * The HP Pavilion x2 10 series comes in a number of variants:
> + * Bay Trail SoC    + AXP288 PMIC, DMI_BOARD_NAME: "815D"
> + * Cherry Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "813E"
> + * Cherry Trail SoC + TI PMIC,     DMI_BOARD_NAME: "827C" or "82F4"
> + *
> + * The variants with the AXP288 PMIC are all kinds of special:
> + *
> + * 1. All variants use a Type-C connector which the AXP288 does not support, so
> + * when using a Type-C charger it is not recognized. Unlike most AXP288 devices,
> + * this model actually has mostly working ACPI AC / Battery code, the ACPI code
> + * "solves" this by simply setting the input_current_limit to 3A.
> + * There are still some issues with the ACPI code, so we use this native driver,
> + * and to solve the charging not working (500mA is not enough) issue we hardcode
> + * the 3A input_current_limit like the ACPI code does.
> + *
> + * 2. If no charger is connected the machine boots with the vbus-path disabled.
> + * Normally this is done when a 5V boost converter is active to avoid the PMIC
> + * trying to charge from the 5V boost converter's output. This is done when
> + * an OTG host cable is inserted and the ID pin on the micro-B receptacle is
> + * pulled low and the ID pin has an ACPI event handler associated with it
> + * which re-enables the vbus-path when the ID pin is pulled high when the
> + * OTG host cable is removed. The Type-C connector has no ID pin, there is
> + * no ID pin handler and there appears to be no 5V boost converter, so we
> + * end up not charging because the vbus-path is disabled, until we unplug
> + * the charger which automatically clears the vbus-path disable bit and then
> + * on the second plug-in of the adapter we start charging. To solve the not
> + * charging on first charger plugin we unconditionally enable the vbus-path at
> + * probe on this model, which is safe since there is no 5V boost converter.
> + */
> +static const struct dmi_system_id axp288_hp_x2_dmi_ids[] = {
> +	{
> +		/*
> +		 * Bay Trail model has "Hewlett-Packard" as sys_vendor, Cherry
> +		 * Trail model has "HP", so we only match on product_name.
> +		 */
> +		.matches = {
> +			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
> +		},
> +	},
> +	{} /* Terminating entry */
> +};
> +
>  static void axp288_charger_extcon_evt_worker(struct work_struct *work)
>  {
>  	struct axp288_chrg_info *info =
> @@ -568,7 +612,11 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work)
>  	}
>  
>  	/* Determine cable/charger type */
> -	if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
> +	if (dmi_check_system(axp288_hp_x2_dmi_ids)) {
> +		/* See comment above axp288_hp_x2_dmi_ids declaration */
> +		dev_dbg(&info->pdev->dev, "HP X2 with Type-C, setting inlmt to 3A\n");
> +		current_limit = 3000000;
> +	} else if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
>  		dev_dbg(&info->pdev->dev, "USB SDP charger is connected\n");
>  		current_limit = 500000;
>  	} else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) {
> @@ -685,6 +733,13 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info)
>  		return ret;
>  	}
>  
> +	if (dmi_check_system(axp288_hp_x2_dmi_ids)) {
> +		/* See comment above axp288_hp_x2_dmi_ids declaration */
> +		ret = axp288_charger_vbus_path_select(info, true);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>  	/* Read current charge voltage and current limit */
>  	ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val);
>  	if (ret < 0) {
> -- 
> 2.25.0
> 

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux