[PATCH linux v5 3/5] drivers: hwmon OCC scom bus operations

eajames.ibm at gmail.com eajames.ibm at gmail.com
Tue Nov 8 10:15:54 AEDT 2016


From: "Edward A. James" <eajames at us.ibm.com>

Add i2c bus operations to perform scom functions

Signed-off-by: Edward A. James <eajames at us.ibm.com>
---
 drivers/hwmon/occ/occ.c     | 23 ++++++++++++++-
 drivers/hwmon/occ/occ.h     |  4 ++-
 drivers/hwmon/occ/occ_i2c.c | 72 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/hwmon/occ/p8.c      |  4 +--
 drivers/hwmon/occ/p8.h      |  4 ++-
 drivers/hwmon/occ/p9.c      |  4 +--
 drivers/hwmon/occ/p9.h      |  4 ++-
 drivers/hwmon/occ/scom.h    | 31 +++++++++++++++++++
 8 files changed, 137 insertions(+), 9 deletions(-)
 create mode 100644 drivers/hwmon/occ/scom.h

diff --git a/drivers/hwmon/occ/occ.c b/drivers/hwmon/occ/occ.c
index 4969915..733b935c 100644
--- a/drivers/hwmon/occ/occ.c
+++ b/drivers/hwmon/occ/occ.c
@@ -30,13 +30,34 @@
 
 #include "occ.h"
 
-int occ_start(struct device *dev)
+struct occ_driver {
+	void *bus;
+	struct occ_bus_ops bus_ops;
+};
+
+int occ_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops)
 {
+	struct occ_driver *driver = devm_kzalloc(dev,
+						 sizeof(struct occ_driver),
+						 GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, driver);
+
+	driver->bus = bus;
+	driver->bus_ops = bus_ops;
+
 	return 0;
 }
 
 int occ_stop(struct device *dev)
 {
+	struct occ_driver *driver = dev_get_drvdata(dev);
+
+	if (driver)
+		devm_kfree(dev, driver);
+
 	return 0;
 }
 
diff --git a/drivers/hwmon/occ/occ.h b/drivers/hwmon/occ/occ.h
index 736d3b9..3232251 100644
--- a/drivers/hwmon/occ/occ.h
+++ b/drivers/hwmon/occ/occ.h
@@ -20,9 +20,11 @@
 #ifndef __OCC_H__
 #define __OCC_H__
 
+#include "scom.h"
+
 struct device;
 
-int occ_start(struct device *dev);
+int occ_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops);
 int occ_stop(struct device *dev);
 
 #endif /* __OCC_H__ */
diff --git a/drivers/hwmon/occ/occ_i2c.c b/drivers/hwmon/occ/occ_i2c.c
index 7659ea1..7c20bc3 100644
--- a/drivers/hwmon/occ/occ_i2c.c
+++ b/drivers/hwmon/occ/occ_i2c.c
@@ -25,14 +25,84 @@
 #include <linux/kernel.h>
 #include <linux/device.h>
 
+#include "scom.h"
 #include "p8.h"
 
 #define OCC_I2C_NAME	"occ-p8-i2c"
 
+#define I2C_READ_ERROR	1
+#define I2C_WRITE_ERROR	2
+
+/*
+ * occ_i2c_getscom - helper function for scom read over i2c to OCC
+ * @bus: handle to slave device
+ * @address: address
+ * @data: where to store data read from slave; buffer size must be greater than
+ * or equal to offset + 8 bytes.
+ * @offset: offset into data pointer
+ *
+ * Returns 0 on success or -1 on read error, -2 on write error
+ */
+int occ_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset)
+{
+	ssize_t rc;
+	u64 buf;
+	struct i2c_client *client = bus;
+
+	/* P8 i2c slave requires address to be shifted by 1 */
+	address = address << 1;
+
+	rc = i2c_master_send(client, (const char *)&address, sizeof(u32));
+	if (rc != sizeof(u32))
+		return -I2C_WRITE_ERROR;
+
+	rc = i2c_master_recv(client, (char *)&buf, sizeof(u64));
+	if (rc != sizeof(u64))
+		return -I2C_READ_ERROR;
+
+	*((u64 *)&data[offset]) = be64_to_cpu(buf);
+
+	return 0;
+}
+
+/*
+ * occ_i2c_putscom - helper function for scom write over i2c to OCC
+ * @bus: handle to slave device
+ * @address: address
+ * @data0: first data byte to write
+ * @data1: second data byte to write
+ *
+ * Returns 0 on success or -2 on error
+ */
+int occ_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1)
+{
+	u32 buf[3];
+	ssize_t rc;
+	struct i2c_client *client = bus;
+
+	/* P8 i2c slave requires address to be shifted by 1 */
+	address = address << 1;
+
+	buf[0] = address;
+	buf[1] = data1;
+	buf[2] = data0;
+
+	rc = i2c_master_send(client, (const char *)buf, sizeof(u32) * 3);
+	if (rc != sizeof(u32) * 3)
+		return -I2C_WRITE_ERROR;
+
+	return 0;
+}
+
 static int occ_i2c_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
-	return p8_occ_start(&client->dev);
+	struct occ_bus_ops bus_ops;
+
+	bus_ops.getscom = occ_i2c_getscom;
+	bus_ops.putscom = occ_i2c_putscom;
+
+	return p8_occ_start(&client->dev, client, bus_ops);
 }
 
 static int occ_i2c_remove(struct i2c_client *client)
diff --git a/drivers/hwmon/occ/p8.c b/drivers/hwmon/occ/p8.c
index 6d854bc..6ff6764 100644
--- a/drivers/hwmon/occ/p8.c
+++ b/drivers/hwmon/occ/p8.c
@@ -28,9 +28,9 @@
 
 #include "occ.h"
 
-int p8_occ_start(struct device *dev)
+int p8_occ_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops)
 {
-	return occ_start(dev);
+	return occ_start(dev, bus, bus_ops);
 }
 
 int p8_occ_stop(struct device *dev)
diff --git a/drivers/hwmon/occ/p8.h b/drivers/hwmon/occ/p8.h
index e6941e4..91190d2 100644
--- a/drivers/hwmon/occ/p8.h
+++ b/drivers/hwmon/occ/p8.h
@@ -19,9 +19,11 @@
 #ifndef __P8_H__
 #define __P8_H__
 
+#include "scom.h"
+
 struct device;
 
-int p8_occ_start(struct device *dev);
+int p8_occ_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops);
 int p8_occ_stop(struct device *dev);
 
 #endif /* __P8_H__ */
diff --git a/drivers/hwmon/occ/p9.c b/drivers/hwmon/occ/p9.c
index 065d9bb..f1aa8ac 100644
--- a/drivers/hwmon/occ/p9.c
+++ b/drivers/hwmon/occ/p9.c
@@ -28,9 +28,9 @@
 
 #include "occ.h"
 
-int p9_occ_start(struct device *dev)
+int p9_occ_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops)
 {
-	return occ_start(dev);
+	return occ_start(dev, bus, bus_ops);
 }
 
 int p9_occ_stop(struct device *dev)
diff --git a/drivers/hwmon/occ/p9.h b/drivers/hwmon/occ/p9.h
index 62fe95a..0de37fa 100644
--- a/drivers/hwmon/occ/p9.h
+++ b/drivers/hwmon/occ/p9.h
@@ -19,9 +19,11 @@
 #ifndef __P9_H__
 #define __P9_H__
 
+#include "scom.h"
+
 struct device;
 
-int p9_occ_start(struct device *dev);
+int p9_occ_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops);
 int p9_occ_stop(struct device *dev);
 
 #endif /* __P9_H__ */
diff --git a/drivers/hwmon/occ/scom.h b/drivers/hwmon/occ/scom.h
new file mode 100644
index 0000000..7732c71
--- /dev/null
+++ b/drivers/hwmon/occ/scom.h
@@ -0,0 +1,31 @@
+/*
+ * scom.h - hwmon OCC driver
+ *
+ * This file contains data structures for scom operations to the OCC
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SCOM_H__
+#define __SCOM_H__
+
+/*
+ * occ_bus_ops - represent the low-level transfer methods to communicate with
+ * the OCC.
+ */
+struct occ_bus_ops {
+	int (*getscom)(void *bus, u32 address, u8 *data, size_t offset);
+	int (*putscom)(void *bus, u32 address, u32 data0, u32 data1);
+};
+
+#endif /* __SCOM_H__ */
-- 
1.9.1



More information about the openbmc mailing list