public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Eddie James <eajames@linux.ibm.com>
To: joel@jms.id.au
Cc: broonie@kernel.org, jk@ozlabs.org, alistair@popple.id.au,
	linux-kernel@vger.kernel.org, linux-fsi@lists.ozlabs.org,
	eajames@linux.ibm.com
Subject: [PATCH 2/5] regmap: Add IBM I2CR support
Date: Fri, 14 Oct 2022 17:05:37 -0500	[thread overview]
Message-ID: <20221014220540.55570-3-eajames@linux.ibm.com> (raw)
In-Reply-To: <20221014220540.55570-1-eajames@linux.ibm.com>

Add regmap support for the IBM I2CR. The I2CR (I2C Responder) is an
I2C end-point device that provides access to an IBM POWER CFAM, which
has traditionally been accessed over FSI.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
---
 drivers/base/regmap/Kconfig           |   4 +
 drivers/base/regmap/Makefile          |   1 +
 drivers/base/regmap/regmap-ibm-i2cr.c | 159 ++++++++++++++++++++++++++
 include/linux/regmap.h                |  35 ++++++
 4 files changed, 199 insertions(+)
 create mode 100644 drivers/base/regmap/regmap-ibm-i2cr.c

diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index cd4bb642b9de..71af079a1b67 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -69,3 +69,7 @@ config REGMAP_SPI_AVMM
 config REGMAP_FSI
 	tristate
 	depends on FSI
+
+config REGMAP_IBM_I2CR
+	tristate
+	depends on I2C
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 6990de7ca9a9..871069903ad5 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
 obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
 obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o
 obj-$(CONFIG_REGMAP_FSI) += regmap-fsi.o
+obj-$(CONFIG_REGMAP_IBM_I2CR) += regmap-ibm-i2cr.o
diff --git a/drivers/base/regmap/regmap-ibm-i2cr.c b/drivers/base/regmap/regmap-ibm-i2cr.c
new file mode 100644
index 000000000000..799ad9e43a45
--- /dev/null
+++ b/drivers/base/regmap/regmap-ibm-i2cr.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Register map access API - IBM I2CR for POWER CFAM access
+//
+// Copyright 2022 IBM Corp
+//
+// Author: Eddie James <eajames@linux.ibm.com>
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "internal.h"
+
+#define I2CR_STATUS		0x30001
+#define  I2CR_STATUS_ERR	 BIT(29)
+
+static bool i2cr_check_parity(u32 v, bool parity)
+{
+	u32 i;
+
+	for (i = 0; i < 32; ++i) {
+		if (v & (1 << i))
+			parity = !parity;
+	}
+
+	return parity;
+}
+
+static __be32 i2cr_get_command(u32 address, bool parity)
+{
+	address <<= 1;
+
+	if (i2cr_check_parity(address, parity))
+		address |= 1;
+
+	return cpu_to_be32(address);
+}
+
+static int i2cr_transfer(struct i2c_client *client, u32 address, u32 *data)
+{
+	struct i2c_msg msgs[2];
+	__be32 response[2];
+	__be32 command;
+	int ret;
+
+	command = i2cr_get_command(address, false);
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(command);
+	msgs[0].buf = (__u8 *)&command;
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(response);
+	msgs[1].buf = (__u8 *)response;
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret == 2) {
+		*data = be32_to_cpu(response[0]);
+		return 0;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return -EIO;
+}
+
+static int i2cr_check_status(struct i2c_client *client)
+{
+	u32 status;
+	int ret;
+
+	ret = i2cr_transfer(client, I2CR_STATUS, &status);
+	if (ret)
+		return ret;
+
+	if (status & I2CR_STATUS_ERR)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int regmap_ibm_i2cr_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct i2c_client *client = context;
+	int ret;
+	u32 v;
+
+	ret = i2cr_transfer(client, (u32)reg, &v);
+	if (ret)
+		return ret;
+
+	*val = v;
+	return i2cr_check_status(client);
+}
+
+static int regmap_ibm_i2cr_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct i2c_client *client = context;
+	__be32 data[3];
+	int ret;
+
+	data[0] = i2cr_get_command((u32)reg, i2cr_check_parity((u32)val, false));
+	data[1] = cpu_to_be32((u32)val);
+
+	ret = i2c_master_send(client, (const char *)data, sizeof(data));
+	if (ret == sizeof(data))
+		return i2cr_check_status(client);
+
+	if (ret < 0)
+		return ret;
+
+	return -EIO;
+}
+
+static const struct regmap_bus regmap_ibm_i2cr = {
+	.reg_write = regmap_ibm_i2cr_reg_write,
+	.reg_read = regmap_ibm_i2cr_reg_read,
+};
+
+static const struct regmap_bus *regmap_get_ibm_i2cr_bus(struct i2c_client *client,
+							const struct regmap_config *config)
+{
+	const struct regmap_bus *bus = NULL;
+
+	if (config->reg_bits == 32 && config->val_bits == 32)
+		bus = &regmap_ibm_i2cr;
+
+	return bus ?: ERR_PTR(-EOPNOTSUPP);
+}
+
+struct regmap *__regmap_init_ibm_i2cr(struct i2c_client *client,
+				      const struct regmap_config *config,
+				      struct lock_class_key *lock_key, const char *lock_name)
+{
+	const struct regmap_bus *bus = regmap_get_ibm_i2cr_bus(client, config);
+
+	if (IS_ERR(bus))
+		return ERR_CAST(bus);
+
+	return __regmap_init(&client->dev, bus, client, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__regmap_init_ibm_i2cr);
+
+struct regmap *__devm_regmap_init_ibm_i2cr(struct i2c_client *client,
+					   const struct regmap_config *config,
+					   struct lock_class_key *lock_key, const char *lock_name)
+{
+	const struct regmap_bus *bus = regmap_get_ibm_i2cr_bus(client, config);
+
+	if (IS_ERR(bus))
+		return ERR_CAST(bus);
+
+	return __devm_regmap_init(&client->dev, bus, client, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_ibm_i2cr);
+
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index e477112fb1c7..1821ebfa640c 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -633,6 +633,10 @@ struct regmap *__regmap_init_fsi(struct fsi_device *fsi_dev,
 				 const struct regmap_config *config,
 				 struct lock_class_key *lock_key,
 				 const char *lock_name);
+struct regmap *__regmap_init_ibm_i2cr(struct i2c_client *client,
+				      const struct regmap_config *config,
+				      struct lock_class_key *lock_key,
+				      const char *lock_name);
 
 struct regmap *__devm_regmap_init(struct device *dev,
 				  const struct regmap_bus *bus,
@@ -702,6 +706,10 @@ struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev,
 				      const struct regmap_config *config,
 				      struct lock_class_key *lock_key,
 				      const char *lock_name);
+struct regmap *__devm_regmap_init_ibm_i2cr(struct i2c_client *client,
+					   const struct regmap_config *config,
+					   struct lock_class_key *lock_key,
+					   const char *lock_name);
 
 /*
  * Wrapper for regmap_init macros to include a unique lockdep key and name
@@ -942,6 +950,19 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
 	__regmap_lockdep_wrapper(__regmap_init_fsi, #config, fsi_dev,	\
 				 config)
 
+/**
+ * regmap_init_ibm_i2cr() - Initialise register map
+ *
+ * @client: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+#define regmap_init_ibm_i2cr(client, config)				\
+	__regmap_lockdep_wrapper(__regmap_init_ibm_i2cr, #config,	\
+				 client, config)
+
 /**
  * devm_regmap_init() - Initialise managed register map
  *
@@ -1185,6 +1206,20 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
 	__regmap_lockdep_wrapper(__devm_regmap_init_fsi, #config,	\
 				 fsi_dev, config)
 
+/**
+ * devm_regmap_init_ibm_i2cr() - Initialise managed register map
+ *
+ * @client: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+#define devm_regmap_init_ibm_i2cr(client, config)			\
+	__regmap_lockdep_wrapper(__devm_regmap_init_ibm_i2cr, #config,	\
+				 client, config)
+
 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk);
 void regmap_mmio_detach_clk(struct regmap *map);
 void regmap_exit(struct regmap *map);
-- 
2.31.1


  parent reply	other threads:[~2022-10-14 22:06 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-14 22:05 [PATCH 0/5] fsi: Add regmap and refactor sbefifo Eddie James
2022-10-14 22:05 ` [PATCH 1/5] regmap: Add FSI bus support Eddie James
2022-10-14 22:05 ` Eddie James [this message]
2022-10-14 22:05 ` [PATCH 3/5] drivers: fsi: Rename sbefifo and occ sources Eddie James
2022-10-14 22:05 ` [PATCH 4/5] drivers: fsi: separate char device code for occ and sbefifo Eddie James
2022-10-17 20:53   ` kernel test robot
2022-10-14 22:05 ` [PATCH 5/5] drivers: fsi: occ and sbefifo refactor Eddie James
2022-10-17 22:34   ` kernel test robot
2022-10-17 23:35   ` kernel test robot
2022-10-18 13:14   ` kernel test robot
2022-10-17 17:37 ` [PATCH 0/5] fsi: Add regmap and refactor sbefifo Mark Brown
2022-10-18 14:02   ` Eddie James
2022-10-18 18:00     ` Mark Brown
2022-10-18 22:03       ` Andrew Jeffery
2022-10-19 18:59       ` Eddie James

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=20221014220540.55570-3-eajames@linux.ibm.com \
    --to=eajames@linux.ibm.com \
    --cc=alistair@popple.id.au \
    --cc=broonie@kernel.org \
    --cc=jk@ozlabs.org \
    --cc=joel@jms.id.au \
    --cc=linux-fsi@lists.ozlabs.org \
    --cc=linux-kernel@vger.kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox