[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