All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.