Skip to content

Commit

Permalink
usb: typec: tps6598x: Add support for polling interrupts status
Browse files Browse the repository at this point in the history
Some development boards don't have the interrupt line connected.

In such cases we can resort to polling the interrupt status.

Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
Signed-off-by: Roger Quadros <rogerq@kernel.org>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20230324131853.41102-1-rogerq@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Aswath Govindraju authored and Greg Kroah-Hartman committed Mar 29, 2023
1 parent 97318d6 commit 0d6a119
Showing 1 changed file with 36 additions and 5 deletions.
41 changes: 36 additions & 5 deletions drivers/usb/typec/tipd/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h>
#include <linux/usb/role.h>
#include <linux/workqueue.h>

#include "tps6598x.h"
#include "trace.h"
Expand Down Expand Up @@ -97,6 +98,8 @@ struct tps6598x {

int wakeup;
u16 pwr_status;
struct delayed_work wq_poll;
irq_handler_t irq_handler;
};

static enum power_supply_property tps6598x_psy_props[] = {
Expand Down Expand Up @@ -558,6 +561,18 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data)
return IRQ_NONE;
}

/* Time interval for Polling */
#define POLL_INTERVAL 500 /* msecs */
static void tps6598x_poll_work(struct work_struct *work)
{
struct tps6598x *tps = container_of(to_delayed_work(work),
struct tps6598x, wq_poll);

tps->irq_handler(0, tps);
queue_delayed_work(system_power_efficient_wq,
&tps->wq_poll, msecs_to_jiffies(POLL_INTERVAL));
}

static int tps6598x_check_mode(struct tps6598x *tps)
{
char mode[5] = { };
Expand Down Expand Up @@ -736,6 +751,7 @@ static int tps6598x_probe(struct i2c_client *client)
TPS_REG_INT_PLUG_EVENT;
}

tps->irq_handler = irq_handler;
/* Make sure the controller has application firmware running */
ret = tps6598x_check_mode(tps);
if (ret)
Expand Down Expand Up @@ -827,18 +843,26 @@ static int tps6598x_probe(struct i2c_client *client)
dev_err(&client->dev, "failed to register partner\n");
}

ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
irq_handler,
IRQF_SHARED | IRQF_ONESHOT,
dev_name(&client->dev), tps);
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
irq_handler,
IRQF_SHARED | IRQF_ONESHOT,
dev_name(&client->dev), tps);
} else {
dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n");
INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work);
queue_delayed_work(system_power_efficient_wq, &tps->wq_poll,
msecs_to_jiffies(POLL_INTERVAL));
}

if (ret)
goto err_disconnect;

i2c_set_clientdata(client, tps);
fwnode_handle_put(fwnode);

tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source");
if (tps->wakeup) {
if (tps->wakeup && client->irq) {
device_init_wakeup(&client->dev, true);
enable_irq_wake(client->irq);
}
Expand Down Expand Up @@ -877,6 +901,9 @@ static int __maybe_unused tps6598x_suspend(struct device *dev)
enable_irq_wake(client->irq);
}

if (!client->irq)
cancel_delayed_work_sync(&tps->wq_poll);

return 0;
}

Expand All @@ -890,6 +917,10 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
enable_irq(client->irq);
}

if (client->irq)
queue_delayed_work(system_power_efficient_wq, &tps->wq_poll,
msecs_to_jiffies(POLL_INTERVAL));

return 0;
}

Expand Down

0 comments on commit 0d6a119

Please sign in to comment.