Commit bcfb7ae3 authored by Samuel Holland's avatar Samuel Holland Committed by Sebastian Reichel

power: supply: axp20x_usb_power: Only poll while offline

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.

As long as VBUS is online, a present->absent transition necessarily
implies an online->offline transition. Since will cause an IRQ, there is
no need to poll while VBUS is online.

To ensure the driver's view of VBUS online status remains accurate,
unconditionally poll once when receiving an IRQ and when resuming. If
VBUS is still online at that time, polling will cease until the next
VBUS_REMOVAL IRQ.
Reviewed-by: default avatarChen-Yu Tsai <wens@csie.org>
Signed-off-by: default avatarSamuel Holland <samuel@sholland.org>
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parent 09aaaec5
......@@ -68,16 +68,32 @@ struct axp20x_usb_power {
struct iio_channel *vbus_i;
struct delayed_work vbus_detect;
unsigned int old_status;
unsigned int 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;
power_supply_changed(power->supply);
mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
return IRQ_HANDLED;
}
......@@ -97,19 +113,13 @@ 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:
if (axp20x_usb_vbus_needs_polling(power))
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;
}
static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val)
{
unsigned int v;
......@@ -515,6 +525,8 @@ static int axp20x_usb_power_resume(struct device *dev)
while (i < power->num_irqs)
enable_irq(power->irqs[i++]);
mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
return 0;
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment