kernel: Patch in i2c, sbefifo, and occ drivers

Change-Id: I845752ca9f64f42f1fc46e14cac90a48f7195ca3
Signed-off-by: Edward A. James <eajames@us.ibm.com>
diff --git a/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch
new file mode 100644
index 0000000..20f66bf
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch
@@ -0,0 +1,194 @@
+From patchwork Wed May 10 15:52:38 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [linux, dev-4.10, v2,
+ 2/6] drivers: i2c: Add port structure to FSI algorithm
+From: eajames@linux.vnet.ibm.com
+X-Patchwork-Id: 760696
+Message-Id: <1494431562-25101-3-git-send-email-eajames@linux.vnet.ibm.com>
+To: openbmc@lists.ozlabs.org
+Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com
+Date: Wed, 10 May 2017 10:52:38 -0500
+
+From: "Edward A. James" <eajames@us.ibm.com>
+
+Add and initialize I2C adapters for each port on the FSI-attached I2C
+master. Ports are defined in the devicetree.
+
+Signed-off-by: Edward A. James <eajames@us.ibm.com>
+---
+ drivers/i2c/busses/i2c-fsi.c | 113 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 112 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
+index 3c1087d..cdebc99 100644
+--- a/drivers/i2c/busses/i2c-fsi.c
++++ b/drivers/i2c/busses/i2c-fsi.c
+@@ -30,6 +30,7 @@
+ #define SETFIELD(m, v, val)	\
+ 	(((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
+ 
++#define I2C_MASTER_NR_OFFSET	100
+ #define I2C_DEFAULT_CLK_DIV	6
+ 
+ /* i2c registers */
+@@ -131,9 +132,21 @@
+ 
+ struct fsi_i2c_master {
+ 	struct fsi_device	*fsi;
++	int			idx;
+ 	u8			fifo_size;
++	struct list_head	ports;
++	struct ida		ida;
+ };
+ 
++struct fsi_i2c_port {
++	struct list_head	list;
++	struct i2c_adapter	adapter;
++	struct fsi_i2c_master	*master;
++	u16			port;
++};
++
++static DEFINE_IDA(fsi_i2c_ida);
++
+ static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
+ 			    u32 *data)
+ {
+@@ -188,9 +201,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 -ENOSYS;
+ }
+ 
+@@ -207,13 +255,59 @@ static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
+ static int fsi_i2c_probe(struct device *dev)
+ {
+ 	struct fsi_i2c_master *i2c;
+-	int rc;
++	struct fsi_i2c_port *port;
++	struct device_node *np;
++	int rc, idx;
++	u32 port_no;
+ 
+ 	i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ 	if (!i2c)
+ 		return -ENOMEM;
+ 
+ 	i2c->fsi = to_fsi_dev(dev);
++	i2c->idx = ida_simple_get(&fsi_i2c_ida, 1, INT_MAX, GFP_KERNEL);
++	ida_init(&i2c->ida);
++	INIT_LIST_HEAD(&i2c->ports);
++
++	if (dev->of_node) {
++		/* add adapter for each i2c port of the master */
++		for_each_child_of_node(dev->of_node, np) {
++			rc = of_property_read_u32(np, "port", &port_no);
++			if (rc || port_no > 0xFFFF)
++				continue;
++
++			/* make sure we don't overlap index with a buggy dts */
++			idx = ida_simple_get(&i2c->ida, port_no,
++					     port_no + 1, GFP_KERNEL);
++			if (idx < 0)
++				continue;
++
++			port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
++			if (!port)
++				return -ENOMEM;
++
++			port->master = i2c;
++			port->port = (u16)port_no;
++
++			port->adapter.owner = THIS_MODULE;
++			port->adapter.dev.parent = dev;
++			port->adapter.algo = &fsi_i2c_algorithm;
++			port->adapter.algo_data = port;
++			/* number ports uniquely */
++			port->adapter.nr = (i2c->idx * I2C_MASTER_NR_OFFSET) +
++				port_no;
++
++			snprintf(port->adapter.name,
++				 sizeof(port->adapter.name),
++				 "fsi_i2c-%u", port_no);
++
++			rc = i2c_add_numbered_adapter(&port->adapter);
++			if (rc < 0)
++				return rc;
++
++			list_add(&port->list, &i2c->ports);
++		}
++	}
+ 
+ 	rc = fsi_i2c_dev_init(i2c);
+ 	if (rc)
+@@ -224,6 +318,22 @@ 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);
++	}
++
++	ida_destroy(&i2c->ida);
++
++	ida_simple_remove(&fsi_i2c_ida, i2c->idx);
++
++	return 0;
++}
++
+ static const struct fsi_device_id fsi_i2c_ids[] = {
+ 	{ FSI_ENGID_I2C_FSI, FSI_VERSION_ANY },
+ 	{ 0 }
+@@ -235,6 +345,7 @@ static int fsi_i2c_probe(struct device *dev)
+ 		.name = "i2c_master_fsi",
+ 		.bus = &fsi_bus_type,
+ 		.probe = fsi_i2c_probe,
++		.remove = fsi_i2c_remove,
+ 	},
+ };
+