From: Wilson Ding <dingwei@marvell.com>
To: <linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>
Cc: <andrew@lunn.ch>, <gregory.clement@bootlin.com>,
<sebastian.hesselbarth@gmail.com>, <robh@kernel.org>,
<krzk+dt@kernel.org>, <conor+dt@kernel.org>,
<p.zabel@pengutronix.de>, <salee@marvell.com>,
<gakula@marvell.com>, Wilson Ding <dingwei@marvell.com>
Subject: [PATCH 1/4] [PATCH 1/4] reset: simple: Add syscon device compatible
Date: Thu, 13 Feb 2025 22:58:30 -0800 [thread overview]
Message-ID: <20250214065833.530276-3-dingwei@marvell.com> (raw)
In-Reply-To: <20250214065833.530276-1-dingwei@marvell.com>
Introduce the new ops for updating reset line and getting status. Thus,
the reset controller can be accessed through either direct I/O or regmap
interfaces. It enables the support of the syscon devices with the simple
reset code. To adapt the DT binding of the syscon device, the number of
reset lines must be specified in device data.
Signed-off-by: Wilson Ding <dingwei@marvell.com>
---
drivers/reset/reset-simple.c | 117 +++++++++++++++++++++++------
include/linux/reset/reset-simple.h | 11 +++
2 files changed, 107 insertions(+), 21 deletions(-)
diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c
index 276067839830..e4e777d40a79 100644
--- a/drivers/reset/reset-simple.c
+++ b/drivers/reset/reset-simple.c
@@ -15,8 +15,10 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/spinlock.h>
@@ -27,10 +29,9 @@ to_reset_simple_data(struct reset_controller_dev *rcdev)
return container_of(rcdev, struct reset_simple_data, rcdev);
}
-static int reset_simple_update(struct reset_controller_dev *rcdev,
+static int reset_simple_update_mmio(struct reset_simple_data *data,
unsigned long id, bool assert)
{
- struct reset_simple_data *data = to_reset_simple_data(rcdev);
int reg_width = sizeof(u32);
int bank = id / (reg_width * BITS_PER_BYTE);
int offset = id % (reg_width * BITS_PER_BYTE);
@@ -51,16 +52,40 @@ static int reset_simple_update(struct reset_controller_dev *rcdev,
return 0;
}
+static int reset_simple_update_regmap(struct reset_simple_data *data,
+ unsigned long id, bool assert)
+{
+ int reg_width = sizeof(u32);
+ int bank = id / (reg_width * BITS_PER_BYTE);
+ int offset = id % (reg_width * BITS_PER_BYTE);
+ u32 mask, val;
+
+ mask = BIT(offset);
+
+ if (assert ^ data->active_low)
+ val = mask;
+ else
+ val = 0;
+
+ return regmap_write_bits(data->regmap,
+ data->reg_offset + (bank * reg_width),
+ mask, val);
+}
+
static int reset_simple_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
- return reset_simple_update(rcdev, id, true);
+ struct reset_simple_data *data = to_reset_simple_data(rcdev);
+
+ return data->ops.update(data, id, true);
}
static int reset_simple_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
- return reset_simple_update(rcdev, id, false);
+ struct reset_simple_data *data = to_reset_simple_data(rcdev);
+
+ return data->ops.update(data, id, false);
}
static int reset_simple_reset(struct reset_controller_dev *rcdev,
@@ -81,10 +106,9 @@ static int reset_simple_reset(struct reset_controller_dev *rcdev,
return reset_simple_deassert(rcdev, id);
}
-static int reset_simple_status(struct reset_controller_dev *rcdev,
- unsigned long id)
+static int reset_simple_status_mmio(struct reset_simple_data *data,
+ unsigned long id)
{
- struct reset_simple_data *data = to_reset_simple_data(rcdev);
int reg_width = sizeof(u32);
int bank = id / (reg_width * BITS_PER_BYTE);
int offset = id % (reg_width * BITS_PER_BYTE);
@@ -95,6 +119,31 @@ static int reset_simple_status(struct reset_controller_dev *rcdev,
return !(reg & BIT(offset)) ^ !data->status_active_low;
}
+static int reset_simple_status_regmap(struct reset_simple_data *data,
+ unsigned long id)
+{
+ int reg_width = sizeof(u32);
+ int bank = id / (reg_width * BITS_PER_BYTE);
+ int offset = id % (reg_width * BITS_PER_BYTE);
+ u32 reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, data->reg_offset + (bank * reg_width),
+ ®);
+ if (ret)
+ return ret;
+
+ return !(reg & BIT(offset)) ^ !data->status_active_low;
+}
+
+static int reset_simple_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct reset_simple_data *data = to_reset_simple_data(rcdev);
+
+ return data->ops.status(data, id);
+}
+
const struct reset_control_ops reset_simple_ops = {
.assert = reset_simple_assert,
.deassert = reset_simple_deassert,
@@ -118,6 +167,7 @@ struct reset_simple_devdata {
u32 nr_resets;
bool active_low;
bool status_active_low;
+ bool syscon_dev;
};
#define SOCFPGA_NR_BANKS 8
@@ -171,26 +221,51 @@ static int reset_simple_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
- membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
- if (IS_ERR(membase))
- return PTR_ERR(membase);
+ if (devdata && devdata->syscon_dev) {
+ data->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
- spin_lock_init(&data->lock);
- data->membase = membase;
- data->rcdev.owner = THIS_MODULE;
- data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE;
- data->rcdev.ops = &reset_simple_ops;
- data->rcdev.of_node = dev->of_node;
+ if (device_property_read_u32(&pdev->dev, "offset",
+ &data->reg_offset))
+ data->reg_offset = devdata->reg_offset;
- if (devdata) {
- reg_offset = devdata->reg_offset;
- if (devdata->nr_resets)
- data->rcdev.nr_resets = devdata->nr_resets;
+ if (devdata->nr_resets == 0) {
+ dev_err(dev, "no reset line\n");
+ return -EINVAL;
+ }
+
+ data->rcdev.nr_resets = devdata->nr_resets;
data->active_low = devdata->active_low;
data->status_active_low = devdata->status_active_low;
+
+ data->ops.update = reset_simple_update_regmap;
+ data->ops.status = reset_simple_status_regmap;
+ } else {
+ membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(membase))
+ return PTR_ERR(membase);
+ data->membase = membase;
+ data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE;
+
+ if (devdata) {
+ reg_offset = devdata->reg_offset;
+ if (devdata->nr_resets)
+ data->rcdev.nr_resets = devdata->nr_resets;
+ data->active_low = devdata->active_low;
+ data->status_active_low = devdata->status_active_low;
+ }
+
+ data->membase += reg_offset;
+
+ data->ops.update = reset_simple_update_mmio;
+ data->ops.status = reset_simple_status_mmio;
}
- data->membase += reg_offset;
+ spin_lock_init(&data->lock);
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.ops = &reset_simple_ops;
+ data->rcdev.of_node = dev->of_node;
return devm_reset_controller_register(dev, &data->rcdev);
}
diff --git a/include/linux/reset/reset-simple.h b/include/linux/reset/reset-simple.h
index c3e44f45b0f7..cbcf9e364dd4 100644
--- a/include/linux/reset/reset-simple.h
+++ b/include/linux/reset/reset-simple.h
@@ -13,9 +13,17 @@
#define __RESET_SIMPLE_H__
#include <linux/io.h>
+#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <linux/spinlock.h>
+struct reset_simple_data;
+
+struct reset_simple_line_ops {
+ int (*update)(struct reset_simple_data *data, unsigned long id, bool assert);
+ int (*status)(struct reset_simple_data *data, unsigned long id);
+};
+
/**
* struct reset_simple_data - driver data for simple reset controllers
* @lock: spinlock to protect registers during read-modify-write cycles
@@ -37,6 +45,9 @@
struct reset_simple_data {
spinlock_t lock;
void __iomem *membase;
+ struct regmap *regmap;
+ u32 reg_offset;
+ struct reset_simple_line_ops ops;
struct reset_controller_dev rcdev;
bool active_low;
bool status_active_low;
--
2.43.0
next prev parent reply other threads:[~2025-02-14 6:59 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-14 6:58 [PATCH 0/4] Add Armada8K reset controller support Wilson Ding
2025-02-14 6:58 ` Wilson Ding
2025-02-14 6:58 ` Wilson Ding [this message]
2025-02-14 8:48 ` [PATCH 1/4] [PATCH 1/4] reset: simple: Add syscon device compatible Krzysztof Kozlowski
2025-02-14 11:54 ` Philipp Zabel
2025-02-14 17:13 ` Wilson Ding
2025-02-14 18:03 ` Philipp Zabel
2025-02-14 18:40 ` [EXTERNAL] " Wilson Ding
2025-02-14 6:58 ` [PATCH 2/4] [PATCH 2/4] reset: simple: Add support for Armada8K reset controller Wilson Ding
2025-02-14 8:48 ` Krzysztof Kozlowski
2025-02-14 6:58 ` [PATCH 3/4] [PATCH 3/4] dt-bindings: cp110: Document the " Wilson Ding
2025-02-14 8:45 ` Krzysztof Kozlowski
2025-02-14 6:58 ` [PATCH 4/4] [PATCH 4/4] arm64: dts: marvell: cp11x: Add reset controller node Wilson Ding
2025-02-14 8:48 ` Krzysztof Kozlowski
2025-02-19 0:42 ` [PATCH 0/4] Add Armada8K reset controller support Rob Herring (Arm)
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=20250214065833.530276-3-dingwei@marvell.com \
--to=dingwei@marvell.com \
--cc=andrew@lunn.ch \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=gakula@marvell.com \
--cc=gregory.clement@bootlin.com \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=p.zabel@pengutronix.de \
--cc=robh@kernel.org \
--cc=salee@marvell.com \
--cc=sebastian.hesselbarth@gmail.com \
/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