Skip to content

Commit 1143d41

Browse files
jgstroudgregkh
authored andcommitted
usb: misc: onboard_usb_dev: Fix usb5744 initialization sequence
Introduce i2c APIs to read/write for proper configuration register programming. It ensures that read-modify-write sequence is performed and reserved bit in Runtime Flags 2 register are not touched. Also legacy smbus block write inserted an extra count value into the i2c data stream which breaks the register write on the usb5744. Switching to new read/write i2c APIs fixes both issues. Fixes: 6782311 ("usb: misc: onboard_usb_dev: add Microchip usb5744 SMBus programming support") Cc: stable <[email protected]> Signed-off-by: Jonathan Stroud <[email protected]> Co-developed-by: Radhey Shyam Pandey <[email protected]> Signed-off-by: Radhey Shyam Pandey <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d01ccb5 commit 1143d41

File tree

1 file changed

+87
-13
lines changed

1 file changed

+87
-13
lines changed

drivers/usb/misc/onboard_usb_dev.c

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@
3636
#define USB5744_CMD_CREG_ACCESS 0x99
3737
#define USB5744_CMD_CREG_ACCESS_LSB 0x37
3838
#define USB5744_CREG_MEM_ADDR 0x00
39+
#define USB5744_CREG_MEM_RD_ADDR 0x04
3940
#define USB5744_CREG_WRITE 0x00
40-
#define USB5744_CREG_RUNTIMEFLAGS2 0x41
41-
#define USB5744_CREG_RUNTIMEFLAGS2_LSB 0x1D
41+
#define USB5744_CREG_READ 0x01
42+
#define USB5744_CREG_RUNTIMEFLAGS2 0x411D
4243
#define USB5744_CREG_BYPASS_UDC_SUSPEND BIT(3)
4344

4445
static void onboard_dev_attach_usb_driver(struct work_struct *work);
@@ -309,32 +310,105 @@ static void onboard_dev_attach_usb_driver(struct work_struct *work)
309310
pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err));
310311
}
311312

313+
static int onboard_dev_5744_i2c_read_byte(struct i2c_client *client, u16 addr, u8 *data)
314+
{
315+
struct i2c_msg msg[2];
316+
u8 rd_buf[3];
317+
int ret;
318+
319+
u8 wr_buf[7] = {0, USB5744_CREG_MEM_ADDR, 4,
320+
USB5744_CREG_READ, 1,
321+
addr >> 8 & 0xff,
322+
addr & 0xff};
323+
msg[0].addr = client->addr;
324+
msg[0].flags = 0;
325+
msg[0].len = sizeof(wr_buf);
326+
msg[0].buf = wr_buf;
327+
328+
ret = i2c_transfer(client->adapter, msg, 1);
329+
if (ret < 0)
330+
return ret;
331+
332+
wr_buf[0] = USB5744_CMD_CREG_ACCESS;
333+
wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB;
334+
wr_buf[2] = 0;
335+
msg[0].len = 3;
336+
337+
ret = i2c_transfer(client->adapter, msg, 1);
338+
if (ret < 0)
339+
return ret;
340+
341+
wr_buf[0] = 0;
342+
wr_buf[1] = USB5744_CREG_MEM_RD_ADDR;
343+
msg[0].len = 2;
344+
345+
msg[1].addr = client->addr;
346+
msg[1].flags = I2C_M_RD;
347+
msg[1].len = 2;
348+
msg[1].buf = rd_buf;
349+
350+
ret = i2c_transfer(client->adapter, msg, 2);
351+
if (ret < 0)
352+
return ret;
353+
*data = rd_buf[1];
354+
355+
return 0;
356+
}
357+
358+
static int onboard_dev_5744_i2c_write_byte(struct i2c_client *client, u16 addr, u8 data)
359+
{
360+
struct i2c_msg msg[2];
361+
int ret;
362+
363+
u8 wr_buf[8] = {0, USB5744_CREG_MEM_ADDR, 5,
364+
USB5744_CREG_WRITE, 1,
365+
addr >> 8 & 0xff,
366+
addr & 0xff,
367+
data};
368+
msg[0].addr = client->addr;
369+
msg[0].flags = 0;
370+
msg[0].len = sizeof(wr_buf);
371+
msg[0].buf = wr_buf;
372+
373+
ret = i2c_transfer(client->adapter, msg, 1);
374+
if (ret < 0)
375+
return ret;
376+
377+
msg[0].len = 3;
378+
wr_buf[0] = USB5744_CMD_CREG_ACCESS;
379+
wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB;
380+
wr_buf[2] = 0;
381+
382+
ret = i2c_transfer(client->adapter, msg, 1);
383+
if (ret < 0)
384+
return ret;
385+
386+
return 0;
387+
}
388+
312389
static int onboard_dev_5744_i2c_init(struct i2c_client *client)
313390
{
314391
#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV_USB5744)
315392
struct device *dev = &client->dev;
316393
int ret;
394+
u8 reg;
317395

318396
/*
319397
* Set BYPASS_UDC_SUSPEND bit to ensure MCU is always enabled
320398
* and ready to respond to SMBus runtime commands.
321399
* The command writes 5 bytes to memory and single data byte in
322400
* configuration register.
323401
*/
324-
char wr_buf[7] = {USB5744_CREG_MEM_ADDR, 5,
325-
USB5744_CREG_WRITE, 1,
326-
USB5744_CREG_RUNTIMEFLAGS2,
327-
USB5744_CREG_RUNTIMEFLAGS2_LSB,
328-
USB5744_CREG_BYPASS_UDC_SUSPEND};
329-
330-
ret = i2c_smbus_write_block_data(client, 0, sizeof(wr_buf), wr_buf);
402+
ret = onboard_dev_5744_i2c_read_byte(client,
403+
USB5744_CREG_RUNTIMEFLAGS2, &reg);
331404
if (ret)
332-
return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit configuration failed\n");
405+
return dev_err_probe(dev, ret, "CREG_RUNTIMEFLAGS2 read failed\n");
333406

334-
ret = i2c_smbus_write_word_data(client, USB5744_CMD_CREG_ACCESS,
335-
USB5744_CMD_CREG_ACCESS_LSB);
407+
reg |= USB5744_CREG_BYPASS_UDC_SUSPEND;
408+
ret = onboard_dev_5744_i2c_write_byte(client,
409+
USB5744_CREG_RUNTIMEFLAGS2, reg);
336410
if (ret)
337-
return dev_err_probe(dev, ret, "Configuration Register Access Command failed\n");
411+
return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit configuration failed\n");
338412

339413
/* Send SMBus command to boot hub. */
340414
ret = i2c_smbus_write_word_data(client, USB5744_CMD_ATTACH,

0 commit comments

Comments
 (0)