Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1684567 > unrolled thread
| Started by | Eddie James <eajames@linux.vnet.ibm.com> |
|---|---|
| First post | 2017-07-10 20:40 +0200 |
| Last post | 2017-07-17 16:20 +0200 |
| Articles | 7 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm Eddie James <eajames@linux.vnet.ibm.com> - 2017-07-10 20:40 +0200
[PATCH v2 2/6] drivers/i2c: Add port structure to FSI algorithm Eddie James <eajames@linux.vnet.ibm.com> - 2017-07-10 20:40 +0200
[PATCH v2 3/6] drivers/i2c: Add transfer implementation for FSI algorithm Eddie James <eajames@linux.vnet.ibm.com> - 2017-07-10 20:50 +0200
Re: [PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm Joel Stanley <joel@jms.id.au> - 2017-07-17 16:20 +0200
Re: [PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm Greg KH <gregkh@linuxfoundation.org> - 2017-07-17 16:30 +0200
Re: [PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm Wolfram Sang <wsa@the-dreams.de> - 2017-07-17 16:30 +0200
Re: [PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm Greg KH <gregkh@linuxfoundation.org> - 2017-07-17 16:20 +0200
| From | Eddie James <eajames@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-07-10 20:40 +0200 |
| Subject | [PATCH v2 0/6] drivers/i2c: Add FSI-attached I2C master algorithm |
| Message-ID | <u1LLc-94-7@gated-at.bofh.it> |
From: "Edward A. James" <eajames@us.ibm.com> This series adds an algorithm for an I2C master physically located on an FSI slave device. The I2C master has multiple ports, each of which may be connected to an I2C slave. Access to the I2C master registers is achieved over FSI bus. Due to the multi-port nature of the I2C master, the driver instantiates a new I2C adapter for each port connected to a slave. The connected ports should be defined in the device tree under the I2C master device. Changes since v1: * Switch "port" to "i2c-bus" for child nodes in the dt. * Switch "port" to "reg" dt property. * Add example device under i2c-bus node in docs. * Set of_node of I2C adapter. * Use dynamically allocated numbering for I2C adapters. * Remove ida counters; unnecessary. Edward A. James (6): drivers/i2c: Add FSI-attached I2C master algorithm drivers/i2c: Add port structure to FSI algorithm drivers/i2c: Add transfer implementation for FSI algorithm drivers/i2c: Add I2C master locking to FSI algorithm drivers/i2c: Add bus recovery for FSI algorithm dt-bindings: i2c: Add FSI-attached I2C master dt binding documentation Documentation/devicetree/bindings/i2c/i2c-fsi.txt | 40 ++ drivers/i2c/busses/Kconfig | 11 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-fsi.c | 637 ++++++++++++++++++++++ 4 files changed, 689 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-fsi.txt create mode 100644 drivers/i2c/busses/i2c-fsi.c -- 1.8.3.1
[toc] | [next] | [standalone]
| From | Eddie James <eajames@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-07-10 20:40 +0200 |
| Subject | [PATCH v2 2/6] drivers/i2c: Add port structure to FSI algorithm |
| Message-ID | <u1LLd-94-51@gated-at.bofh.it> |
| In reply to | #1684567 |
From: "Edward A. James" <eajames@us.ibm.com>
Add and initialize I2C adapters for each port on the FSI-attached I2C
master. Ports for each master are defined in the devicetree.
Signed-off-by: Edward A. James <eajames@us.ibm.com>
---
drivers/i2c/busses/i2c-fsi.c | 91 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index b7f2bc6..4b52147 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -14,7 +14,9 @@
#include <linux/fsi.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
#define FSI_ENGID_I2C 0x7
@@ -130,6 +132,14 @@
struct fsi_i2c_master {
struct fsi_device *fsi;
u8 fifo_size;
+ struct list_head ports;
+};
+
+struct fsi_i2c_port {
+ struct list_head list;
+ struct i2c_adapter adapter;
+ struct fsi_i2c_master *master;
+ u16 port;
};
static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
@@ -186,9 +196,44 @@ static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c)
return rc;
}
+static int fsi_i2c_set_port(struct fsi_i2c_port *port)
+{
+ int rc;
+ struct fsi_device *fsi = port->master->fsi;
+ u32 mode, dummy = 0;
+ u16 old_port;
+
+ rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return rc;
+
+ old_port = GETFIELD(I2C_MODE_PORT, mode);
+
+ if (old_port != port->port) {
+ mode = SETFIELD(I2C_MODE_PORT, mode, port->port);
+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return rc;
+
+ /* reset engine when port is changed */
+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy);
+ if (rc)
+ return rc;
+ }
+
+ return rc;
+}
+
static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
+ int rc;
+ struct fsi_i2c_port *port = adap->algo_data;
+
+ rc = fsi_i2c_set_port(port);
+ if (rc)
+ return rc;
+
return -EOPNOTSUPP;
}
@@ -205,13 +250,46 @@ static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
static int fsi_i2c_probe(struct device *dev)
{
struct fsi_i2c_master *i2c;
+ struct fsi_i2c_port *port;
+ struct device_node *np;
int rc;
+ u32 port_no;
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
i2c->fsi = to_fsi_dev(dev);
+ INIT_LIST_HEAD(&i2c->ports);
+
+ /* Add adapter for each i2c port of the master. */
+ for_each_available_child_of_node(dev->of_node, np) {
+ rc = of_property_read_u32(np, "reg", &port_no);
+ if (rc || port_no > USHRT_MAX)
+ continue;
+
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ port->master = i2c;
+ port->port = port_no;
+
+ port->adapter.owner = THIS_MODULE;
+ port->adapter.dev.of_node = np;
+ port->adapter.dev.parent = dev;
+ port->adapter.algo = &fsi_i2c_algorithm;
+ port->adapter.algo_data = port;
+
+ snprintf(port->adapter.name, sizeof(port->adapter.name),
+ "i2c_bus-%u", port_no);
+
+ rc = i2c_add_adapter(&port->adapter);
+ if (rc < 0)
+ return rc;
+
+ list_add(&port->list, &i2c->ports);
+ }
rc = fsi_i2c_dev_init(i2c);
if (rc)
@@ -222,6 +300,18 @@ static int fsi_i2c_probe(struct device *dev)
return 0;
}
+static int fsi_i2c_remove(struct device *dev)
+{
+ struct fsi_i2c_master *i2c = dev_get_drvdata(dev);
+ struct fsi_i2c_port *port;
+
+ list_for_each_entry(port, &i2c->ports, list) {
+ i2c_del_adapter(&port->adapter);
+ }
+
+ return 0;
+}
+
static const struct fsi_device_id fsi_i2c_ids[] = {
{ FSI_ENGID_I2C, FSI_VERSION_ANY },
{ 0 }
@@ -233,6 +323,7 @@ static int fsi_i2c_probe(struct device *dev)
.name = "i2c-fsi",
.bus = &fsi_bus_type,
.probe = fsi_i2c_probe,
+ .remove = fsi_i2c_remove,
},
};
--
1.8.3.1
[toc] | [prev] | [next] | [standalone]
| From | Eddie James <eajames@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-07-10 20:50 +0200 |
| Subject | [PATCH v2 3/6] drivers/i2c: Add transfer implementation for FSI algorithm |
| Message-ID | <u1LUS-cs-15@gated-at.bofh.it> |
| In reply to | #1684567 |
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
[toc] | [prev] | [next] | [standalone]
| From | Joel Stanley <joel@jms.id.au> |
|---|---|
| Date | 2017-07-17 16:20 +0200 |
| Message-ID | <u4f2p-69R-15@gated-at.bofh.it> |
| In reply to | #1684567 |
On Mon, Jul 17, 2017 at 11:41 PM, Greg KH <gregkh@linuxfoundation.org> wrote: > On Mon, Jul 10, 2017 at 01:37:56PM -0500, Eddie James wrote: >> From: "Edward A. James" <eajames@us.ibm.com> >> >> This series adds an algorithm for an I2C master physically located on an FSI >> slave device. The I2C master has multiple ports, each of which may be connected >> to an I2C slave. Access to the I2C master registers is achieved over FSI bus. >> >> Due to the multi-port nature of the I2C master, the driver instantiates a new >> I2C adapter for each port connected to a slave. The connected ports should be >> defined in the device tree under the I2C master device. >> >> Changes since v1: > > I have 2 "v2" series in my inbox, and they are different :( > > Please resend a "v4" so I know exactly which ones to pick up... Hi Greg, This is a driver for the i2c bus master, so I would expect the patches to be reviewed and applied through Wolfram's i2c tree? Eddie, regardless can you please send a v4 so we know which version to be reviewing. Cheers, Joel
[toc] | [prev] | [next] | [standalone]
| From | Greg KH <gregkh@linuxfoundation.org> |
|---|---|
| Date | 2017-07-17 16:30 +0200 |
| Message-ID | <u4fc6-6e7-15@gated-at.bofh.it> |
| In reply to | #1689089 |
On Mon, Jul 17, 2017 at 04:20:13PM +0200, Wolfram Sang wrote: > > > This is a driver for the i2c bus master, so I would expect the patches > > to be reviewed and applied through Wolfram's i2c tree? > > Yes, please. > Ok, then why are people sending them to me? I'll gladly let others take them :) thanks, greg k-h
[toc] | [prev] | [next] | [standalone]
| From | Wolfram Sang <wsa@the-dreams.de> |
|---|---|
| Date | 2017-07-17 16:30 +0200 |
| Message-ID | <u4fc6-6e7-17@gated-at.bofh.it> |
| In reply to | #1689089 |
[Multipart message — attachments visible in raw view] — view raw
> This is a driver for the i2c bus master, so I would expect the patches > to be reviewed and applied through Wolfram's i2c tree? Yes, please.
[toc] | [prev] | [next] | [standalone]
| From | Greg KH <gregkh@linuxfoundation.org> |
|---|---|
| Date | 2017-07-17 16:20 +0200 |
| Message-ID | <u4f2p-69R-17@gated-at.bofh.it> |
| In reply to | #1684567 |
On Mon, Jul 10, 2017 at 01:37:56PM -0500, Eddie James wrote: > From: "Edward A. James" <eajames@us.ibm.com> > > This series adds an algorithm for an I2C master physically located on an FSI > slave device. The I2C master has multiple ports, each of which may be connected > to an I2C slave. Access to the I2C master registers is achieved over FSI bus. > > Due to the multi-port nature of the I2C master, the driver instantiates a new > I2C adapter for each port connected to a slave. The connected ports should be > defined in the device tree under the I2C master device. > > Changes since v1: I have 2 "v2" series in my inbox, and they are different :( Please resend a "v4" so I know exactly which ones to pick up... thanks, gre k-h
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web