From: Eddie James <eajames@linux.vnet.ibm.com>
To: linux-kernel@vger.kernel.org
Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org,
wsa@the-dreams.de, robh+dt@kernel.org,
gregkh@linuxfoundation.org, jk@ozlabs.org, joel@jms.id.au,
andrew@aj.id.au, eajames@linux.vnet.ibm.com,
cbostic@linux.vnet.ibm.com,
"Edward A. James" <eajames@us.ibm.com>
Subject: [PATCH v2 3/6] drivers/i2c: Add transfer implementation for FSI algorithm
Date: Mon, 10 Jul 2017 13:37:59 -0500 [thread overview]
Message-ID: <1499711882-12918-4-git-send-email-eajames@linux.vnet.ibm.com> (raw)
In-Reply-To: <1499711882-12918-1-git-send-email-eajames@linux.vnet.ibm.com>
From: "Edward A. James" <eajames@us.ibm.com>
Execute I2C transfers from the FSI-attached I2C master. Use polling
instead of interrupts as we have no hardware IRQ over FSI.
Signed-off-by: Edward A. James <eajames@us.ibm.com>
---
drivers/i2c/busses/i2c-fsi.c | 197 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 195 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index 4b52147..f86595b 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -13,10 +13,12 @@
#include <linux/errno.h>
#include <linux/fsi.h>
#include <linux/i2c.h>
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/sched.h>
#define FSI_ENGID_I2C 0x7
@@ -140,6 +142,7 @@ struct fsi_i2c_port {
struct i2c_adapter adapter;
struct fsi_i2c_master *master;
u16 port;
+ u16 xfrd;
};
static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
@@ -224,17 +227,207 @@ static int fsi_i2c_set_port(struct fsi_i2c_port *port)
return rc;
}
+static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ bool stop)
+{
+ int rc;
+ struct fsi_i2c_master *i2c = port->master;
+ u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR;
+
+ port->xfrd = 0;
+
+ if (msg->flags & I2C_M_RD)
+ cmd |= I2C_CMD_READ;
+
+ if (stop || msg->flags & I2C_M_STOP)
+ cmd |= I2C_CMD_WITH_STOP;
+
+ cmd = SETFIELD(I2C_CMD_ADDR, cmd, msg->addr >> 1);
+ cmd = SETFIELD(I2C_CMD_LEN, cmd, msg->len);
+
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd);
+
+ return rc;
+}
+
+static int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ u8 fifo_count)
+{
+ int write;
+ int rc = 0;
+ struct fsi_i2c_master *i2c = port->master;
+ int bytes_to_write = i2c->fifo_size - fifo_count;
+ int bytes_remaining = msg->len - port->xfrd;
+
+ if (bytes_to_write > bytes_remaining)
+ bytes_to_write = bytes_remaining;
+
+ while (bytes_to_write > 0) {
+ write = bytes_to_write;
+ /* fsi limited to max 4 byte aligned ops */
+ if (bytes_to_write > 4)
+ write = 4;
+ else if (write == 3)
+ write = 2;
+
+ rc = fsi_device_write(i2c->fsi, I2C_FSI_FIFO,
+ &msg->buf[port->xfrd], write);
+ if (rc)
+ return rc;
+
+ port->xfrd += write;
+ bytes_to_write -= write;
+ }
+
+ return rc;
+}
+
+static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ u8 fifo_count)
+{
+ int read;
+ int rc = 0;
+ struct fsi_i2c_master *i2c = port->master;
+ int xfr_remaining = msg->len - port->xfrd;
+ u32 dummy;
+
+ while (fifo_count) {
+ read = fifo_count;
+ /* fsi limited to max 4 byte aligned ops */
+ if (fifo_count > 4)
+ read = 4;
+ else if (read == 3)
+ read = 2;
+
+ if (xfr_remaining) {
+ if (xfr_remaining < read)
+ read = xfr_remaining;
+
+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO,
+ &msg->buf[port->xfrd], read);
+ if (rc)
+ return rc;
+
+ port->xfrd += read;
+ xfr_remaining -= read;
+ } else {
+ /* no more buffer but data in fifo, need to clear it */
+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, &dummy,
+ read);
+ if (rc)
+ return rc;
+ }
+
+ fifo_count -= read;
+ }
+
+ return rc;
+}
+
+static int fsi_i2c_handle_status(struct fsi_i2c_port *port,
+ struct i2c_msg *msg, u32 status)
+{
+ int rc;
+ u8 fifo_count;
+ struct fsi_i2c_master *i2c = port->master;
+ u32 dummy = 0;
+
+ if (status & I2C_STAT_ERR) {
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy);
+ if (rc)
+ return rc;
+
+ if (status & I2C_STAT_NACK)
+ return -EFAULT;
+
+ return -EIO;
+ }
+
+ if (status & I2C_STAT_DAT_REQ) {
+ fifo_count = GETFIELD(I2C_STAT_FIFO_COUNT, status);
+
+ if (msg->flags & I2C_M_RD)
+ rc = fsi_i2c_read_fifo(port, msg, fifo_count);
+ else
+ rc = fsi_i2c_write_fifo(port, msg, fifo_count);
+
+ return rc;
+ }
+
+ if (status & I2C_STAT_CMD_COMP) {
+ if (port->xfrd < msg->len)
+ rc = -ENODATA;
+ else
+ rc = msg->len;
+
+ return rc;
+ }
+
+ return 0;
+}
+
+static int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ unsigned long timeout)
+{
+ const unsigned long local_timeout = 2; /* jiffies */
+ u32 status = 0;
+ int rc;
+
+ do {
+ rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT,
+ &status);
+ if (rc)
+ return rc;
+
+ if (status & I2C_STAT_ANY_RESP) {
+ rc = fsi_i2c_handle_status(port, msg, status);
+ if (rc < 0)
+ return rc;
+
+ /* cmd complete and all data xfrd */
+ if (rc == msg->len)
+ return 0;
+
+ /* need to xfr more data, but maybe don't need wait */
+ continue;
+ }
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(local_timeout);
+ timeout = (timeout < local_timeout) ? 0 :
+ timeout - local_timeout;
+ } while (timeout);
+
+ return -ETIME;
+}
+
static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
- int rc;
+ int i, rc;
+ unsigned long start_time;
struct fsi_i2c_port *port = adap->algo_data;
+ struct i2c_msg *msg;
rc = fsi_i2c_set_port(port);
if (rc)
return rc;
- return -EOPNOTSUPP;
+ for (i = 0; i < num; ++i) {
+ msg = msgs + i;
+ start_time = jiffies;
+
+ rc = fsi_i2c_start(port, msg, i == num - 1);
+ if (rc)
+ return rc;
+
+ rc = fsi_i2c_wait(port, msg,
+ adap->timeout - (jiffies - start_time));
+ if (rc)
+ return rc;
+ }
+
+ return 0;
}
static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
--
1.8.3.1
next prev parent reply other threads:[~2017-07-10 18:37 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-10 18:37 [PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm Eddie James
2017-07-10 18:37 ` [PATCH v2 2/6] drivers/i2c: Add port structure to FSI algorithm Eddie James
2017-07-10 18:37 ` Eddie James [this message]
[not found] ` <1499711882-12918-1-git-send-email-eajames-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-10 18:37 ` [PATCH v2 1/6] drivers/i2c: Add FSI-attached I2C master algorithm Eddie James
2017-07-10 18:37 ` Eddie James
2017-07-10 18:38 ` [PATCH v2 4/6] drivers/i2c: Add I2C master locking to FSI algorithm Eddie James
2017-07-10 18:38 ` Eddie James
2017-07-10 18:38 ` [PATCH v2 5/6] drivers/i2c: Add bus recovery for " Eddie James
2017-07-10 18:38 ` [PATCH v2 6/6] dt-bindings: i2c: Add FSI-attached I2C master dt binding documentation Eddie James
2017-07-14 16:05 ` Rob Herring
2017-07-17 14:11 ` [PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm Greg KH
2017-07-17 14:16 ` Joel Stanley
2017-07-17 14:20 ` Wolfram Sang
2017-07-17 14:26 ` Greg KH
2017-07-17 14:26 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1499711882-12918-4-git-send-email-eajames@linux.vnet.ibm.com \
--to=eajames@linux.vnet.ibm.com \
--cc=andrew@aj.id.au \
--cc=cbostic@linux.vnet.ibm.com \
--cc=devicetree@vger.kernel.org \
--cc=eajames@us.ibm.com \
--cc=gregkh@linuxfoundation.org \
--cc=jk@ozlabs.org \
--cc=joel@jms.id.au \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=robh+dt@kernel.org \
--cc=wsa@the-dreams.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.