Skip to content

Commit 5f8838e

Browse files
committed
HID: i2c-hid: Suspend i2c-hid devices in remove
In the i2c-hid remove() function we currently try to power off, depopulate our child device, and free our resources. That's OK, but... * If the i2c-hid device is on a power rail that can't turn off (either an always-on or a shared power rail) we won't try to put the device in a low power state during remove(). This probably doesn't matter for very many devices but it could be nice in some instances. * If the i2c-hid device somehow manages to generate an interrupt after we tried to power off it is conceivable that the interrupt could arrive during or after the call to hid_destroy_device() but before the call to free_irq(). That could cause a crash since our IRQ handler isn't expecting it. One could imagine this happening in the case where we couldn't turn off (see the previous bullet) or, possibly, if the interrupt line could glitch shortly after the device powered off. Let's call the suspend code during remove to avoid these issues. That will put the device into a low power state and also disable interrupts. Technically, one could consider this a "fix" of commit 4a200c3 ("HID: i2c-hid: introduce HID over i2c specification implementation"). However, since the above bullet points are more theoretical than problems seen on real systems and since the remove() of an i2c-hid touchscreen isn't terribly likely to be called in production, it's probably not worth the bother of trying to backport it. Reviewed-by: Benjamin Tissoires <[email protected]> Acked-by: Benjamin Tissoires <[email protected]> Signed-off-by: Douglas Anderson <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/20230727101636.v4.8.Ic3ecad4a825905f4e4ce2a772b17f3c9cb2d60a2@changeid
1 parent d93d284 commit 5f8838e

File tree

1 file changed

+4
-4
lines changed

1 file changed

+4
-4
lines changed

drivers/hid/i2c-hid/i2c-hid-core.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ static void i2c_hid_core_shutdown_tail(struct i2c_hid *ihid)
941941
ihid->ops->shutdown_tail(ihid->ops);
942942
}
943943

944-
static int i2c_hid_core_suspend(struct i2c_hid *ihid)
944+
static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff)
945945
{
946946
struct i2c_client *client = ihid->client;
947947
struct hid_device *hid = ihid->hid;
@@ -956,7 +956,7 @@ static int i2c_hid_core_suspend(struct i2c_hid *ihid)
956956

957957
disable_irq(client->irq);
958958

959-
if (!device_may_wakeup(&client->dev))
959+
if (force_poweroff || !device_may_wakeup(&client->dev))
960960
i2c_hid_core_power_down(ihid);
961961

962962
return 0;
@@ -1143,7 +1143,7 @@ void i2c_hid_core_remove(struct i2c_client *client)
11431143
struct i2c_hid *ihid = i2c_get_clientdata(client);
11441144
struct hid_device *hid;
11451145

1146-
i2c_hid_core_power_down(ihid);
1146+
i2c_hid_core_suspend(ihid, true);
11471147

11481148
hid = ihid->hid;
11491149
hid_destroy_device(hid);
@@ -1171,7 +1171,7 @@ static int i2c_hid_core_pm_suspend(struct device *dev)
11711171
struct i2c_client *client = to_i2c_client(dev);
11721172
struct i2c_hid *ihid = i2c_get_clientdata(client);
11731173

1174-
return i2c_hid_core_suspend(ihid);
1174+
return i2c_hid_core_suspend(ihid, false);
11751175
}
11761176

11771177
static int i2c_hid_core_pm_resume(struct device *dev)

0 commit comments

Comments
 (0)