Skip to content

Commit dfae9a2

Browse files
hamishm-atlnzgregkh
authored andcommitted
HID: mcp2221: Don't set bus speed on every transfer
commit 02a4675 upstream. Since the initial commit of this driver the I2C bus speed has been reconfigured for every single transfer. This is despite the fact that we never change the speed and it is never "lost" by the chip. Upon investigation we find that what was really happening was that the setting of the bus speed had the side effect of cancelling a previous failed command if there was one, thereby freeing the bus. This is the part that was actually required to keep the bus operational in the face of failed commands. Instead of always setting the speed, we now correctly cancel any failed commands as they are detected. This means we can just set the bus speed at probe time and remove the previous speed sets on each transfer. This has the effect of improving performance and reducing the number of commands required to complete transfers. Signed-off-by: Hamish Martin <hamish.martin@alliedtelesis.co.nz> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Fixes: 67a95c2 ("HID: mcp2221: add usb to i2c-smbus host bridge") [romain.sioen@microchip.com: backport to stable, up to 6.8. Add "Fixes" tag] Signed-off-by: Romain Sioen <romain.sioen@microchip.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 407ae39 commit dfae9a2

1 file changed

Lines changed: 27 additions & 14 deletions

File tree

drivers/hid/hid-mcp2221.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,25 @@ static int mcp_cancel_last_cmd(struct mcp2221 *mcp)
169169
return mcp_send_data_req_status(mcp, mcp->txbuf, 8);
170170
}
171171

172+
/* Check if the last command succeeded or failed and return the result.
173+
* If the command did fail, cancel that command which will free the i2c bus.
174+
*/
175+
static int mcp_chk_last_cmd_status_free_bus(struct mcp2221 *mcp)
176+
{
177+
int ret;
178+
179+
ret = mcp_chk_last_cmd_status(mcp);
180+
if (ret) {
181+
/* The last command was a failure.
182+
* Send a cancel which will also free the bus.
183+
*/
184+
usleep_range(980, 1000);
185+
mcp_cancel_last_cmd(mcp);
186+
}
187+
188+
return ret;
189+
}
190+
172191
static int mcp_set_i2c_speed(struct mcp2221 *mcp)
173192
{
174193
int ret;
@@ -223,7 +242,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
223242
usleep_range(980, 1000);
224243

225244
if (last_status) {
226-
ret = mcp_chk_last_cmd_status(mcp);
245+
ret = mcp_chk_last_cmd_status_free_bus(mcp);
227246
if (ret)
228247
return ret;
229248
}
@@ -290,7 +309,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
290309
if (ret)
291310
return ret;
292311

293-
ret = mcp_chk_last_cmd_status(mcp);
312+
ret = mcp_chk_last_cmd_status_free_bus(mcp);
294313
if (ret)
295314
return ret;
296315

@@ -310,11 +329,6 @@ static int mcp_i2c_xfer(struct i2c_adapter *adapter,
310329

311330
mutex_lock(&mcp->lock);
312331

313-
/* Setting speed before every transaction is required for mcp2221 */
314-
ret = mcp_set_i2c_speed(mcp);
315-
if (ret)
316-
goto exit;
317-
318332
if (num == 1) {
319333
if (msgs->flags & I2C_M_RD) {
320334
ret = mcp_i2c_smbus_read(mcp, msgs, MCP2221_I2C_RD_DATA,
@@ -399,9 +413,7 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr,
399413
if (last_status) {
400414
usleep_range(980, 1000);
401415

402-
ret = mcp_chk_last_cmd_status(mcp);
403-
if (ret)
404-
return ret;
416+
ret = mcp_chk_last_cmd_status_free_bus(mcp);
405417
}
406418

407419
return ret;
@@ -419,10 +431,6 @@ static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
419431

420432
mutex_lock(&mcp->lock);
421433

422-
ret = mcp_set_i2c_speed(mcp);
423-
if (ret)
424-
goto exit;
425-
426434
switch (size) {
427435

428436
case I2C_SMBUS_QUICK:
@@ -870,6 +878,11 @@ static int mcp2221_probe(struct hid_device *hdev,
870878
if (i2c_clk_freq < 50)
871879
i2c_clk_freq = 50;
872880
mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3;
881+
ret = mcp_set_i2c_speed(mcp);
882+
if (ret) {
883+
hid_err(hdev, "can't set i2c speed: %d\n", ret);
884+
return ret;
885+
}
873886

874887
mcp->adapter.owner = THIS_MODULE;
875888
mcp->adapter.class = I2C_CLASS_HWMON;

0 commit comments

Comments
 (0)