Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH] HID: cp2112: add I2C mode
@ 2014-06-29  6:14 Antonio Borneo
  2014-07-07 13:57 ` Benjamin Tissoires
  0 siblings, 1 reply; 6+ messages in thread
From: Antonio Borneo @ 2014-06-29  6:14 UTC (permalink / raw)
  To: Jiri Kosina, linux-input, David Barksdale; +Cc: linux-kernel, Antonio Borneo

cp2112 supports single I2C read/write transactions.
It can't combine I2C transactions.

Add master_xfer, using similar code flow as for smbus_xfer.

Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
---
 drivers/hid/hid-cp2112.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 3952d90..1260a8a 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -429,6 +429,104 @@ static int cp2112_write_req(void *buf, u8 slave_address, u8 command, u8 *data,
 	return data_length + 4;
 }
 
+static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data,
+				u8 data_length)
+{
+	struct cp2112_write_req_report *report = buf;
+
+	if (data_length > sizeof(report->data))
+		return -EINVAL;
+
+	report->report = CP2112_DATA_WRITE_REQUEST;
+	report->slave_address = slave_address << 1;
+	report->length = data_length;
+	memcpy(report->data, data, data_length);
+	return data_length + 3;
+}
+
+static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+			   int num)
+{
+	struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data;
+	struct hid_device *hdev = dev->hdev;
+	u8 buf[64];
+	ssize_t count;
+	unsigned int retries;
+	int ret;
+
+	hid_dbg(hdev, "I2C %d messages\n", num);
+
+	if (num != 1) {
+		hid_err(hdev,
+			"Multi-message I2C transactions not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (msgs->flags & I2C_M_RD)
+		count = cp2112_read_req(buf, msgs->addr, msgs->len);
+	else
+		count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf,
+					     msgs->len);
+
+	if (count < 0)
+		return count;
+
+	ret = hid_hw_power(hdev, PM_HINT_FULLON);
+	if (ret < 0) {
+		hid_err(hdev, "power management error: %d\n", ret);
+		return ret;
+	}
+
+	ret = cp2112_hid_output(hdev, buf, count, HID_OUTPUT_REPORT);
+	if (ret < 0) {
+		hid_warn(hdev, "Error starting transaction: %d\n", ret);
+		goto power_normal;
+	}
+
+	for (retries = 0; retries < XFER_STATUS_RETRIES; ++retries) {
+		ret = cp2112_xfer_status(dev);
+		if (-EBUSY == ret)
+			continue;
+		if (ret < 0)
+			goto power_normal;
+		break;
+	}
+
+	if (XFER_STATUS_RETRIES <= retries) {
+		hid_warn(hdev, "Transfer timed out, cancelling.\n");
+		buf[0] = CP2112_CANCEL_TRANSFER;
+		buf[1] = 0x01;
+
+		ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT);
+		if (ret < 0)
+			hid_warn(hdev, "Error cancelling transaction: %d\n",
+				 ret);
+
+		ret = -ETIMEDOUT;
+		goto power_normal;
+	}
+
+	if (!(msgs->flags & I2C_M_RD)) {
+		ret = 0;
+		goto power_normal;
+	}
+
+	ret = cp2112_read(dev, msgs->buf, msgs->len);
+	if (ret < 0)
+		goto power_normal;
+	if (ret != msgs->len) {
+		hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len);
+		ret = -EIO;
+		goto power_normal;
+	}
+
+	ret = 0;
+power_normal:
+	hid_hw_power(hdev, PM_HINT_NORMAL);
+	hid_dbg(hdev, "I2C transfer finished: %d\n", ret);
+	return (ret) ? ret : 1;
+}
+
 static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
 		       unsigned short flags, char read_write, u8 command,
 		       int size, union i2c_smbus_data *data)
@@ -595,7 +693,8 @@ power_normal:
 
 static u32 cp2112_functionality(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_SMBUS_BYTE |
+	return I2C_FUNC_I2C |
+		I2C_FUNC_SMBUS_BYTE |
 		I2C_FUNC_SMBUS_BYTE_DATA |
 		I2C_FUNC_SMBUS_WORD_DATA |
 		I2C_FUNC_SMBUS_BLOCK_DATA |
@@ -605,6 +704,7 @@ static u32 cp2112_functionality(struct i2c_adapter *adap)
 }
 
 static const struct i2c_algorithm smbus_algorithm = {
+	.master_xfer	= cp2112_i2c_xfer,
 	.smbus_xfer	= cp2112_xfer,
 	.functionality	= cp2112_functionality,
 };
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-07-29  9:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-06-29  6:14 [PATCH] HID: cp2112: add I2C mode Antonio Borneo
2014-07-07 13:57 ` Benjamin Tissoires
2014-07-07 15:32   ` Antonio Borneo
2014-07-07 15:52     ` Benjamin Tissoires
2014-07-07 23:25       ` [PATCH v2] " Antonio Borneo
2014-07-29  9:38         ` Jiri Kosina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox