Commit a2caa72f authored by Angus Ainslie's avatar Angus Ainslie Committed by Angus Ainslie
Browse files

usb: typec: tps6598x: mask status update



We don't need the status update unless it's plugged in.

With broken CC lines the cable sometimes shows as plugged in even when it
isn't. Look further into the status register to see if it is connected and
disable the STATUS interrupt to stop the irq storm.
Signed-off-by: default avatarAngus Ainslie <angus@akkea.ca>
parent 1fecf684
......@@ -65,6 +65,8 @@
#define TPS_REG_INT_ATTENTION_RECEIVED BIT(10)
#define TPS_REG_INT_PLUG_EVENT BIT(3)
#define CC_INT_MASK TPS_REG_INT_STATUS_UPDATE
/* TPS_REG_STATUS bits */
#define TPS_STATUS_PLUG_PRESENT BIT(0)
#define TPS_STATUS_ORIENTATION BIT(4)
......@@ -370,6 +372,9 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status)
enum typec_pwr_opmode mode;
u16 pwr_status;
int ret;
u64 mask;
dev_dbg(tps->dev, "%s: status %x", __func__, status);
if (tps->partner)
return 0;
......@@ -407,6 +412,16 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status)
if (desc.identity)
typec_partner_set_identity(tps->partner);
ret = tps6598x_read64(tps, TPS_REG_INT_MASK1, &mask);
if (ret < 0)
return ret;
mask |= CC_INT_MASK;
ret = tps6598x_write64(tps, TPS_REG_INT_MASK1, mask);
if (ret < 0)
return ret;
dev_dbg(tps->dev, "interrupt mask updated %llx", mask);
power_supply_changed(tps->psy);
return 0;
......@@ -438,6 +453,11 @@ tps6598x_update_data_status(struct tps6598x *tps)
static void tps6598x_disconnect(struct tps6598x *tps, u32 status)
{
int ret;
u64 mask;
dev_dbg(tps->dev, "%s: status %x", __func__, status);
if (!IS_ERR(tps->partner))
typec_unregister_partner(tps->partner);
tps->partner = NULL;
......@@ -445,6 +465,20 @@ static void tps6598x_disconnect(struct tps6598x *tps, u32 status)
typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status));
typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status));
tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false);
ret = tps6598x_read64(tps, TPS_REG_INT_MASK1, &mask);
if (ret < 0) {
dev_err(tps->dev, "Reading interrupt mask failed");
return;
}
mask &= ~CC_INT_MASK;
ret = tps6598x_write64(tps, TPS_REG_INT_MASK1, mask);
if (ret < 0) {
dev_err(tps->dev, "Writing interrupt mask failed");
return;
}
dev_dbg(tps->dev, "interrupt mask updated %llx", mask);
power_supply_changed(tps->psy);
}
......@@ -591,6 +625,7 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data)
u64 event2;
u32 status;
int ret;
u64 mask;
mutex_lock(&tps->lock);
......@@ -628,6 +663,26 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data)
}
}
if ((event1 | event2) & TPS_REG_INT_STATUS_UPDATE) {
ret = tps6598x_read64(tps, TPS_REG_INT_MASK1, &mask);
if (ret < 0)
dev_err( tps->dev, "Reading interrupt mask failed");
dev_dbg(tps->dev, "Status update: %x %llx", status, mask);
if (!(mask & TPS_REG_INT_STATUS_UPDATE))
dev_err( tps->dev, "The interrupt is masked , how did it fire ?? %llx", mask);
if (!(status & TPS_STATUS_PLUG_PRESENT) || ((status & 0xc) != 0xc)) {
/* the status update register can fire even when masked so try
and mask it again */
mask &= ~TPS_REG_INT_STATUS_UPDATE;
ret = tps6598x_write64(tps, TPS_REG_INT_MASK1, mask);
if (ret < 0)
dev_err( tps->dev, "Writing interrupt mask failed");
else
dev_dbg( tps->dev, "interrupt mask updated %llx", mask);
}
}
err_clear_ints:
tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event1);
tps6598x_write64(tps, TPS_REG_INT_CLEAR2, event2);
......@@ -757,6 +812,7 @@ static int tps6598x_probe(struct i2c_client *client)
u32 conf;
u32 vid;
int ret;
u64 mask;
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
......@@ -869,12 +925,23 @@ static int tps6598x_probe(struct i2c_client *client)
/* set initial state */
extcon_set_state_sync(tps->extcon, EXTCON_DISP_DP, false);
ret = tps6598x_read64(tps, TPS_REG_INT_MASK1, &mask);
if (ret < 0)
dev_err(&client->dev, "failed to read irq mask%d\n", ret);
if (status & TPS_STATUS_PLUG_PRESENT) {
ret = tps6598x_connect(tps, status);
if (ret)
dev_err(&client->dev, "failed to register partner\n");
} else {
mask &= ~CC_INT_MASK;
}
ret = tps6598x_write64(tps, TPS_REG_INT_MASK1, mask);
ret |= tps6598x_write64(tps, TPS_REG_INT_MASK2, 0);
if (ret < 0)
dev_err(&client->dev, "failed to write irq mask%d\n", ret);
ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
tps6598x_interrupt,
IRQF_SHARED | IRQF_ONESHOT,
......
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