aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEllen Wang <ellen@cumulusnetworks.com>2015-07-10 00:55:06 -0400
committerJiri Kosina <jkosina@suse.com>2015-07-10 05:18:45 -0400
commit44eda784a2229d25e2724ef1734fe67453716231 (patch)
treef9790205b23f4bc5ec1909159b0b4316c77ef437
parent5ddfb12e90c73cf86881345be422e09c367f6981 (diff)
HID: cp2112: support i2c write-read transfers in hid-cp2112
cp2112_i2c_xfer() only supports a single i2c_msg. More than one message at a time just returns EIO. This breaks certain important cases. For example, the at24 eeprom driver generates paired write and read messages (for eeprom address and data). Since the device doesn't support i2c repeated starts in general, but does support a single write-repeated-start-read pair (since hardware rev 1), we recognize the latter case and implement only that. Signed-off-by: Ellen Wang <ellen@cumulusnetworks.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
-rw-r--r--drivers/hid/hid-cp2112.c74
1 files changed, 55 insertions, 19 deletions
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 75398cb84fde..1d24a65b4295 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -156,6 +156,7 @@ struct cp2112_device {
156 wait_queue_head_t wait; 156 wait_queue_head_t wait;
157 u8 read_data[61]; 157 u8 read_data[61];
158 u8 read_length; 158 u8 read_length;
159 u8 hwversion;
159 int xfer_status; 160 int xfer_status;
160 atomic_t read_avail; 161 atomic_t read_avail;
161 atomic_t xfer_avail; 162 atomic_t xfer_avail;
@@ -446,6 +447,24 @@ static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data,
446 return data_length + 3; 447 return data_length + 3;
447} 448}
448 449
450static int cp2112_i2c_write_read_req(void *buf, u8 slave_address,
451 u8 *addr, int addr_length,
452 int read_length)
453{
454 struct cp2112_write_read_req_report *report = buf;
455
456 if (read_length < 1 || read_length > 512 ||
457 addr_length > sizeof(report->target_address))
458 return -EINVAL;
459
460 report->report = CP2112_DATA_WRITE_READ_REQUEST;
461 report->slave_address = slave_address << 1;
462 report->length = cpu_to_be16(read_length);
463 report->target_address_length = addr_length;
464 memcpy(report->target_address, addr, addr_length);
465 return addr_length + 5;
466}
467
449static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 468static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
450 int num) 469 int num)
451{ 470{
@@ -453,26 +472,46 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
453 struct hid_device *hdev = dev->hdev; 472 struct hid_device *hdev = dev->hdev;
454 u8 buf[64]; 473 u8 buf[64];
455 ssize_t count; 474 ssize_t count;
475 ssize_t read_length = 0;
476 u8 *read_buf = NULL;
456 unsigned int retries; 477 unsigned int retries;
457 int ret; 478 int ret;
458 479
459 hid_dbg(hdev, "I2C %d messages\n", num); 480 hid_dbg(hdev, "I2C %d messages\n", num);
460 481
461 if (num != 1) { 482 if (num == 1) {
483 if (msgs->flags & I2C_M_RD) {
484 hid_dbg(hdev, "I2C read %#04x len %d\n",
485 msgs->addr, msgs->len);
486 read_length = msgs->len;
487 read_buf = msgs->buf;
488 count = cp2112_read_req(buf, msgs->addr, msgs->len);
489 } else {
490 hid_dbg(hdev, "I2C write %#04x len %d\n",
491 msgs->addr, msgs->len);
492 count = cp2112_i2c_write_req(buf, msgs->addr,
493 msgs->buf, msgs->len);
494 }
495 if (count < 0)
496 return count;
497 } else if (dev->hwversion > 1 && /* no repeated start in rev 1 */
498 num == 2 &&
499 msgs[0].addr == msgs[1].addr &&
500 !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
501 hid_dbg(hdev, "I2C write-read %#04x wlen %d rlen %d\n",
502 msgs[0].addr, msgs[0].len, msgs[1].len);
503 read_length = msgs[1].len;
504 read_buf = msgs[1].buf;
505 count = cp2112_i2c_write_read_req(buf, msgs[0].addr,
506 msgs[0].buf, msgs[0].len, msgs[1].len);
507 if (count < 0)
508 return count;
509 } else {
462 hid_err(hdev, 510 hid_err(hdev,
463 "Multi-message I2C transactions not supported\n"); 511 "Multi-message I2C transactions not supported\n");
464 return -EOPNOTSUPP; 512 return -EOPNOTSUPP;
465 } 513 }
466 514
467 if (msgs->flags & I2C_M_RD)
468 count = cp2112_read_req(buf, msgs->addr, msgs->len);
469 else
470 count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf,
471 msgs->len);
472
473 if (count < 0)
474 return count;
475
476 ret = hid_hw_power(hdev, PM_HINT_FULLON); 515 ret = hid_hw_power(hdev, PM_HINT_FULLON);
477 if (ret < 0) { 516 if (ret < 0) {
478 hid_err(hdev, "power management error: %d\n", ret); 517 hid_err(hdev, "power management error: %d\n", ret);
@@ -508,11 +547,8 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
508 goto power_normal; 547 goto power_normal;
509 } 548 }
510 549
511 if (!(msgs->flags & I2C_M_RD)) 550 for (count = 0; count < read_length;) {
512 goto finish; 551 ret = cp2112_read(dev, read_buf + count, read_length - count);
513
514 for (count = 0; count < msgs->len;) {
515 ret = cp2112_read(dev, msgs->buf + count, msgs->len - count);
516 if (ret < 0) 552 if (ret < 0)
517 goto power_normal; 553 goto power_normal;
518 if (ret == 0) { 554 if (ret == 0) {
@@ -521,7 +557,7 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
521 goto power_normal; 557 goto power_normal;
522 } 558 }
523 count += ret; 559 count += ret;
524 if (count > msgs->len) { 560 if (count > read_length) {
525 /* 561 /*
526 * The hardware returned too much data. 562 * The hardware returned too much data.
527 * This is mostly harmless because cp2112_read() 563 * This is mostly harmless because cp2112_read()
@@ -531,15 +567,14 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
531 * it shouldn't go unnoticed. 567 * it shouldn't go unnoticed.
532 */ 568 */
533 hid_err(hdev, "long read: %d > %zd\n", 569 hid_err(hdev, "long read: %d > %zd\n",
534 ret, msgs->len - count + ret); 570 ret, read_length - count + ret);
535 ret = -EIO; 571 ret = -EIO;
536 goto power_normal; 572 goto power_normal;
537 } 573 }
538 } 574 }
539 575
540finish:
541 /* return the number of transferred messages */ 576 /* return the number of transferred messages */
542 ret = 1; 577 ret = num;
543 578
544power_normal: 579power_normal:
545 hid_hw_power(hdev, PM_HINT_NORMAL); 580 hid_hw_power(hdev, PM_HINT_NORMAL);
@@ -1047,6 +1082,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
1047 dev->adap.dev.parent = &hdev->dev; 1082 dev->adap.dev.parent = &hdev->dev;
1048 snprintf(dev->adap.name, sizeof(dev->adap.name), 1083 snprintf(dev->adap.name, sizeof(dev->adap.name),
1049 "CP2112 SMBus Bridge on hiddev%d", hdev->minor); 1084 "CP2112 SMBus Bridge on hiddev%d", hdev->minor);
1085 dev->hwversion = buf[2];
1050 init_waitqueue_head(&dev->wait); 1086 init_waitqueue_head(&dev->wait);
1051 1087
1052 hid_device_io_start(hdev); 1088 hid_device_io_start(hdev);