Messages in this thread Patch in this message | | | From | Samuel Holland <> | Subject | [PATCH 7/7] power: supply: axp20x_usb_power: Only poll while offline | Date | Thu, 2 Jan 2020 00:36:33 -0600 |
| |
Investigation on the AXP803 shows that VBUS_PLUGIN/VBUS_REMOVAL IRQs are triggered on the rising/falling edge of AXP20X_PWR_STATUS_VBUS_USED. The reason IRQs do not arrive while N_VBUSEN/DRIVEVBUS is high is because AXP20X_PWR_STATUS_VBUS_USED also never goes high.
This also means that if VBUS is online, a VBUS_REMOVAL IRQ is received immediately on setting N_VBUSEN/DRIVEVBUS high (and VBUS_PLUGIN shortly after it is set back low). This was also verified to be the case when manually offlining VBUS through AXP20X_VBUS_PATH_SELECT.
Therefore, as long as VBUS is online, a present->absent transition necessarily implies an online->offline transition. This will cause an IRQ, and so there is no need to poll.
Signed-off-by: Samuel Holland <samuel@sholland.org> --- drivers/power/supply/axp20x_usb_power.c | 35 ++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 16062b2c7ea8..0993ea03f303 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -67,16 +67,39 @@ struct axp20x_usb_power { struct iio_channel *vbus_i; struct delayed_work vbus_detect; unsigned int old_status; + bool online; unsigned int num_irqs; unsigned int irqs[]; }; +static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power) +{ + /* + * Polling is only necessary while VBUS is offline. While online, a + * present->absent transition implies an online->offline transition + * and will triger the VBUS_REMOVAL IRQ. + */ + if (power->axp20x_id >= AXP221_ID && !power->online) + return true; + + return false; +} + static irqreturn_t axp20x_usb_power_irq(int irq, void *devid) { struct axp20x_usb_power *power = devid; + /* + * VBUS_PLUGIN/VBUS_REMOVAL are triggered on transitions of + * AXP20X_PWR_STATUS_VBUS_USED. + */ + power->online = irq == power->irqs[0]; + power_supply_changed(power->supply); + if (axp20x_usb_vbus_needs_polling(power)) + mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME); + return IRQ_HANDLED; } @@ -96,17 +119,11 @@ static void axp20x_usb_power_poll_vbus(struct work_struct *work) power_supply_changed(power->supply); power->old_status = val; + power->online = val & AXP20X_PWR_STATUS_VBUS_USED; out: - mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME); -} - -static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power) -{ - if (power->axp20x_id >= AXP221_ID) - return true; - - return false; + if (axp20x_usb_vbus_needs_polling(power)) + mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME); } static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val) -- 2.23.0
| |