aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-cp2112.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-cp2112.c')
-rw-r--r--drivers/hid/hid-cp2112.c111
1 files changed, 108 insertions, 3 deletions
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 56be85a9a77c..a822db5a8338 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -240,8 +240,6 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
240 u8 buf[5]; 240 u8 buf[5];
241 int ret; 241 int ret;
242 242
243 cp2112_gpio_set(chip, offset, value);
244
245 ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, 243 ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
246 sizeof(buf), HID_FEATURE_REPORT, 244 sizeof(buf), HID_FEATURE_REPORT,
247 HID_REQ_GET_REPORT); 245 HID_REQ_GET_REPORT);
@@ -260,6 +258,12 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
260 return ret; 258 return ret;
261 } 259 }
262 260
261 /*
262 * Set gpio value when output direction is already set,
263 * as specified in AN495, Rev. 0.2, cpt. 4.4
264 */
265 cp2112_gpio_set(chip, offset, value);
266
263 return 0; 267 return 0;
264} 268}
265 269
@@ -425,6 +429,105 @@ static int cp2112_write_req(void *buf, u8 slave_address, u8 command, u8 *data,
425 return data_length + 4; 429 return data_length + 4;
426} 430}
427 431
432static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data,
433 u8 data_length)
434{
435 struct cp2112_write_req_report *report = buf;
436
437 if (data_length > sizeof(report->data))
438 return -EINVAL;
439
440 report->report = CP2112_DATA_WRITE_REQUEST;
441 report->slave_address = slave_address << 1;
442 report->length = data_length;
443 memcpy(report->data, data, data_length);
444 return data_length + 3;
445}
446
447static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
448 int num)
449{
450 struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data;
451 struct hid_device *hdev = dev->hdev;
452 u8 buf[64];
453 ssize_t count;
454 unsigned int retries;
455 int ret;
456
457 hid_dbg(hdev, "I2C %d messages\n", num);
458
459 if (num != 1) {
460 hid_err(hdev,
461 "Multi-message I2C transactions not supported\n");
462 return -EOPNOTSUPP;
463 }
464
465 if (msgs->flags & I2C_M_RD)
466 count = cp2112_read_req(buf, msgs->addr, msgs->len);
467 else
468 count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf,
469 msgs->len);
470
471 if (count < 0)
472 return count;
473
474 ret = hid_hw_power(hdev, PM_HINT_FULLON);
475 if (ret < 0) {
476 hid_err(hdev, "power management error: %d\n", ret);
477 return ret;
478 }
479
480 ret = cp2112_hid_output(hdev, buf, count, HID_OUTPUT_REPORT);
481 if (ret < 0) {
482 hid_warn(hdev, "Error starting transaction: %d\n", ret);
483 goto power_normal;
484 }
485
486 for (retries = 0; retries < XFER_STATUS_RETRIES; ++retries) {
487 ret = cp2112_xfer_status(dev);
488 if (-EBUSY == ret)
489 continue;
490 if (ret < 0)
491 goto power_normal;
492 break;
493 }
494
495 if (XFER_STATUS_RETRIES <= retries) {
496 hid_warn(hdev, "Transfer timed out, cancelling.\n");
497 buf[0] = CP2112_CANCEL_TRANSFER;
498 buf[1] = 0x01;
499
500 ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT);
501 if (ret < 0)
502 hid_warn(hdev, "Error cancelling transaction: %d\n",
503 ret);
504
505 ret = -ETIMEDOUT;
506 goto power_normal;
507 }
508
509 if (!(msgs->flags & I2C_M_RD))
510 goto finish;
511
512 ret = cp2112_read(dev, msgs->buf, msgs->len);
513 if (ret < 0)
514 goto power_normal;
515 if (ret != msgs->len) {
516 hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len);
517 ret = -EIO;
518 goto power_normal;
519 }
520
521finish:
522 /* return the number of transferred messages */
523 ret = 1;
524
525power_normal:
526 hid_hw_power(hdev, PM_HINT_NORMAL);
527 hid_dbg(hdev, "I2C transfer finished: %d\n", ret);
528 return ret;
529}
530
428static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, 531static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
429 unsigned short flags, char read_write, u8 command, 532 unsigned short flags, char read_write, u8 command,
430 int size, union i2c_smbus_data *data) 533 int size, union i2c_smbus_data *data)
@@ -591,7 +694,8 @@ power_normal:
591 694
592static u32 cp2112_functionality(struct i2c_adapter *adap) 695static u32 cp2112_functionality(struct i2c_adapter *adap)
593{ 696{
594 return I2C_FUNC_SMBUS_BYTE | 697 return I2C_FUNC_I2C |
698 I2C_FUNC_SMBUS_BYTE |
595 I2C_FUNC_SMBUS_BYTE_DATA | 699 I2C_FUNC_SMBUS_BYTE_DATA |
596 I2C_FUNC_SMBUS_WORD_DATA | 700 I2C_FUNC_SMBUS_WORD_DATA |
597 I2C_FUNC_SMBUS_BLOCK_DATA | 701 I2C_FUNC_SMBUS_BLOCK_DATA |
@@ -601,6 +705,7 @@ static u32 cp2112_functionality(struct i2c_adapter *adap)
601} 705}
602 706
603static const struct i2c_algorithm smbus_algorithm = { 707static const struct i2c_algorithm smbus_algorithm = {
708 .master_xfer = cp2112_i2c_xfer,
604 .smbus_xfer = cp2112_xfer, 709 .smbus_xfer = cp2112_xfer,
605 .functionality = cp2112_functionality, 710 .functionality = cp2112_functionality,
606}; 711};