diff mbox series

HID: i2c-hid: wait for i2c touchpad deep-sleep to power-up transition

Message ID 20240325105452.529921-1-lma@chromium.org (mailing list archive)
State Superseded
Delegated to: Jiri Kosina
Headers show
Series HID: i2c-hid: wait for i2c touchpad deep-sleep to power-up transition | expand

Commit Message

Łukasz Majczak March 25, 2024, 10:54 a.m. UTC
This patch extends the early bailout for probing procedure introduced in
commit: b3a81b6c4fc6730ac49e20d789a93c0faabafc98, in order to cover devices
based on STM microcontrollers. For touchpads based on STM uC,
the probe sequence needs to take into account the increased response time
for i2c transaction if the device already entered a deep power state.
STM specify the wakeup time as 400us between positive strobe of
the clock line. Deep sleep is controlled by Touchpad FW,
though some devices enter it pretty early to conserve power
in case of lack of activity on the i2c bus.
Failing to follow this requirement will result in touchpad device not being
detected due initial transaction being dropped by STM i2c slave controller.
By adding additional try, first transaction will wake up the touchpad
STM controller, and the second will produce proper detection response.

Signed-off-by: Lukasz Majczak <lma@chromium.org>
Signed-off-by: Radoslaw Biernacki <rad@chromium.org>
---
 drivers/hid/i2c-hid/i2c-hid-core.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

Comments

Doug Anderson March 25, 2024, 11:12 p.m. UTC | #1
Hi,

On Mon, Mar 25, 2024 at 3:55 AM Lukasz Majczak <lma@chromium.org> wrote:
>
> This patch extends the early bailout for probing procedure introduced in
> commit: b3a81b6c4fc6730ac49e20d789a93c0faabafc98, in order to cover devices

nit: checkpatch should have yelled at you saying that you should
specify a commit in the format:

commit b3a81b6c4fc6 ("HID: i2c-hid: check if device is there before
really probing")

Please fix and make sure that you're running checkpatch.


> based on STM microcontrollers. For touchpads based on STM uC,
> the probe sequence needs to take into account the increased response time
> for i2c transaction if the device already entered a deep power state.
> STM specify the wakeup time as 400us between positive strobe of
> the clock line. Deep sleep is controlled by Touchpad FW,
> though some devices enter it pretty early to conserve power
> in case of lack of activity on the i2c bus.
> Failing to follow this requirement will result in touchpad device not being
> detected due initial transaction being dropped by STM i2c slave controller.
> By adding additional try, first transaction will wake up the touchpad
> STM controller, and the second will produce proper detection response.
>
> Signed-off-by: Lukasz Majczak <lma@chromium.org>
> Signed-off-by: Radoslaw Biernacki <rad@chromium.org>

nit: I believe your sign off should be last. It's also unclear why two
signoffs. Did Radoslaw author it and you changed it? ...or was it
Co-Developed-by, or ...? You'll probably need to adjust your tags a
bit depending on the answers.


> ---
>  drivers/hid/i2c-hid/i2c-hid-core.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)

Overall comment on this patch: I know that this is based on a patch
we've been carrying downstream in ChromeOS for years and some folks
considered it not upstreamable because it's too hacky. My $0.02 is
that, while it's ugly, this is needed to support real hardware that
was shipped. There's zero chance we can fix the hardware, a .00001%
chance that we could convince someone to update the firmware on the
i2c-hid device, and a .01% chance that we could convince people to try
to figure out a workaround by adding something to the main AP firmware
on this device. As I understand it, nobody has come up with a better
kernel workaround than this patch.

To me it doesn't seem terrible to have this retry here and it's not a
huge penalty for other i2c-hid users. ...so personally I'm in favor of
the idea of this landing. If I was a consumer and had one of the
affected Chromebooks I'd personally rather upstream have the support
for it.


> diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
> index 2df1ab3c31cc..69af0fad4f41 100644
> --- a/drivers/hid/i2c-hid/i2c-hid-core.c
> +++ b/drivers/hid/i2c-hid/i2c-hid-core.c
> @@ -1013,9 +1013,15 @@ static int __i2c_hid_core_probe(struct i2c_hid *ihid)
>         struct i2c_client *client = ihid->client;
>         struct hid_device *hid = ihid->hid;
>         int ret;
> +       int tries = 2;
> +
> +       do {
> +               /* Make sure there is something at this address */
> +               ret = i2c_smbus_read_byte(client);
> +               if (tries > 0 && ret < 0)
> +                       usleep_range(400, 400);

Having both ends of the usleep be 400 is iffy. In this case it's at
probe time so I wonder if udelay() is better? If not, maybe give at
least _some_ margin?


> +       } while (tries-- > 0 && ret < 0);

I'm not a huge fan of having to check "tries" and "ret" twice.
Personally I'd rather see a "while (true)" loop and test the condition
once to break out. AKA:

while (true) {
  ret = i2c_...
  tries--;
  if (tries == 0 || ret >= 0)
    break;
  udelay(400);
}

...if you feel very strongly about the way you have coded it, though,
I won't stand in your way.

Pretty much all my comments are just nits and, since I'm not the
maintainer here, my opinion is just an opinion. I'd wait at least a
little while for the maintainers to comment before posting v2. I'm
happy to give a Reviewed-by tag when some of the nits are fixed.

-Doug
Łukasz Majczak March 26, 2024, 8:58 a.m. UTC | #2
> nit: checkpatch should have yelled at you saying that you should
> specify a commit in the format:
>
> commit b3a81b6c4fc6 ("HID: i2c-hid: check if device is there before
> really probing")
>
I will do it, but I did run the checkpatch (with --strict option) and
it didn't complain about anything.

>
> nit: I believe your sign off should be last. It's also unclear why two
> signoffs. Did Radoslaw author it and you changed it? ...or was it
> Co-Developed-by, or ...? You'll probably need to adjust your tags a
> bit depending on the answers.
>
Yes, we've discussed this patch together and the original
investigation was done by Rad.

> Having both ends of the usleep be 400 is iffy. In this case it's at
> probe time so I wonder if udelay() is better? If not, maybe give at
> least _some_ margin?
>
>
> > +       } while (tries-- > 0 && ret < 0);
>
According to Documentation/timers/timers-howto.rst:
" SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms):
                * Use usleep_range"
It was also pointed out by checkpath (when I initially used msleep).
I think giving some margin (eg. 400,500) would be ok.

> I'm not a huge fan of having to check "tries" and "ret" twice.
> Personally I'd rather see a "while (true)" loop and test the condition
> once to break out. AKA:
>
> while (true) {
>   ret = i2c_...
>   tries--;
>   if (tries == 0 || ret >= 0)
>     break;
>   udelay(400);
> }
>
> ...if you feel very strongly about the way you have coded it, though,
> I won't stand in your way.
I don't have emotional bond to this code ;), thanks.
>
> Pretty much all my comments are just nits and, since I'm not the
> maintainer here, my opinion is just an opinion. I'd wait at least a
> little while for the maintainers to comment before posting v2. I'm
> happy to give a Reviewed-by tag when some of the nits are fixed.
>
> -Doug
Thank you Doug for all your input.

Best regards,
Lukasz
Doug Anderson March 26, 2024, 1:43 p.m. UTC | #3
Hi,

On Tue, Mar 26, 2024 at 1:58 AM Łukasz Majczak <lma@chromium.org> wrote:
>
> > nit: checkpatch should have yelled at you saying that you should
> > specify a commit in the format:
> >
> > commit b3a81b6c4fc6 ("HID: i2c-hid: check if device is there before
> > really probing")
> >
> I will do it, but I did run the checkpatch (with --strict option) and
> it didn't complain about anything.

Weird that checkpatch didn't yell, but perhaps somehow your commit
message didn't trigger its regex. ;-)



> > nit: I believe your sign off should be last. It's also unclear why two
> > signoffs. Did Radoslaw author it and you changed it? ...or was it
> > Co-Developed-by, or ...? You'll probably need to adjust your tags a
> > bit depending on the answers.
> >
> Yes, we've discussed this patch together and the original
> investigation was done by Rad.

Sounds good. Probably the best way to tag is these tags in this order:

Co-developed-by: Radoslaw Biernacki <rad@chromium.org>
Signed-off-by: Radoslaw Biernacki <rad@chromium.org>
Signed-off-by: Lukasz Majczak <lma@chromium.org>


> > Having both ends of the usleep be 400 is iffy. In this case it's at
> > probe time so I wonder if udelay() is better? If not, maybe give at
> > least _some_ margin?
> >
> >
> > > +       } while (tries-- > 0 && ret < 0);
> >
> According to Documentation/timers/timers-howto.rst:
> " SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms):
>                 * Use usleep_range"
> It was also pointed out by checkpath (when I initially used msleep).
> I think giving some margin (eg. 400,500) would be ok.

Yeah, usleep_range(400, 500) would be fine. udelay(400) would also be
OK. The later would be more "accurate" but also more wasteful of CPU
cycles. Given that this is at probe time and only run a small handful
of times, it probably doesn't matter lots though perhaps the sleeping
function would allow more parallelism of other running probes.


-Doug
diff mbox series

Patch

diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 2df1ab3c31cc..69af0fad4f41 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -1013,9 +1013,15 @@  static int __i2c_hid_core_probe(struct i2c_hid *ihid)
 	struct i2c_client *client = ihid->client;
 	struct hid_device *hid = ihid->hid;
 	int ret;
+	int tries = 2;
+
+	do {
+		/* Make sure there is something at this address */
+		ret = i2c_smbus_read_byte(client);
+		if (tries > 0 && ret < 0)
+			usleep_range(400, 400);
+	} while (tries-- > 0 && ret < 0);
 
-	/* Make sure there is something at this address */
-	ret = i2c_smbus_read_byte(client);
 	if (ret < 0) {
 		i2c_hid_dbg(ihid, "nothing at this address: %d\n", ret);
 		return -ENXIO;