[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20241126092050.1825607-11-claudiu.beznea.uj@bp.renesas.com>
Date: Tue, 26 Nov 2024 11:20:45 +0200
From: Claudiu <claudiu.beznea@...on.dev>
To: vkoul@...nel.org,
kishon@...nel.org,
robh@...nel.org,
krzk+dt@...nel.org,
conor+dt@...nel.org,
p.zabel@...gutronix.de,
geert+renesas@...der.be,
magnus.damm@...il.com,
gregkh@...uxfoundation.org,
yoshihiro.shimoda.uh@...esas.com,
christophe.jaillet@...adoo.fr
Cc: linux-phy@...ts.infradead.org,
devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-renesas-soc@...r.kernel.org,
linux-usb@...r.kernel.org,
claudiu.beznea@...on.dev,
Claudiu Beznea <claudiu.beznea.uj@...renesas.com>
Subject: [PATCH v2 10/15] phy: renesas: rcar-gen3-usb2: Add support for PWRRDY
From: Claudiu Beznea <claudiu.beznea.uj@...renesas.com>
On the Renesas RZ/G3S SoC, the USB PHY has an input signal called PWRRDY.
This signal is managed by the system controller and must be de-asserted
after powering on the area where USB PHY resides and asserted before
powering it off.
The connection b/w the system controller and the USB PHY is implemented
through the renesas,sysc-signal device tree property. This property
specifies the register offset and the bitmask required to control the
signal. The system controller exports the syscon regmap, and the read/write
access to the memory area of the PWRRDY signal is reference-counted, as the
same system controller signal is connected to both RZ/G3S USB PHYs.
Add support for the PWRRDY signal control.
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@...renesas.com>
---
Changes in v2:
- none; this patch is new
drivers/phy/renesas/phy-rcar-gen3-usb2.c | 66 ++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 59f74aa993ac..84459755adf5 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -12,12 +12,14 @@
#include <linux/extcon-provider.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/string.h>
@@ -111,6 +113,12 @@ struct rcar_gen3_phy {
bool powered;
};
+struct rcar_gen3_pwrrdy {
+ struct regmap *regmap;
+ u32 offset;
+ u32 mask;
+};
+
struct rcar_gen3_chan {
void __iomem *base;
struct device *dev; /* platform_device's device */
@@ -118,6 +126,7 @@ struct rcar_gen3_chan {
struct rcar_gen3_phy rphys[NUM_OF_PHYS];
struct regulator *vbus;
struct reset_control *rstc;
+ struct rcar_gen3_pwrrdy *pwrrdy;
struct work_struct work;
struct mutex lock; /* protects rphys[...].powered */
enum usb_dr_mode dr_mode;
@@ -133,6 +142,7 @@ struct rcar_gen3_phy_drv_data {
const struct phy_ops *phy_usb2_ops;
bool no_adp_ctrl;
bool init_bus;
+ bool pwrrdy;
};
/*
@@ -587,6 +597,7 @@ static const struct rcar_gen3_phy_drv_data rz_g3s_phy_usb2_data = {
.phy_usb2_ops = &rcar_gen3_phy_usb2_ops,
.no_adp_ctrl = true,
.init_bus = true,
+ .pwrrdy = true,
};
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
@@ -707,6 +718,55 @@ static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel)
return ret;
}
+static void rcar_gen3_phy_usb2_set_pwrrdy(struct rcar_gen3_chan *channel, bool power_on)
+{
+ struct rcar_gen3_pwrrdy *pwrrdy = channel->pwrrdy;
+
+ /* N/A on this platform. */
+ if (!pwrrdy)
+ return;
+
+ regmap_update_bits(pwrrdy->regmap, pwrrdy->offset, pwrrdy->mask, !power_on);
+}
+
+static void rcar_gen3_phy_usb2_pwrrdy_off(void *data)
+{
+ rcar_gen3_phy_usb2_set_pwrrdy(data, false);
+}
+
+static int rcar_gen3_phy_usb2_init_pwrrdy(struct rcar_gen3_chan *channel)
+{
+ struct device *dev = channel->dev;
+ struct rcar_gen3_pwrrdy *pwrrdy;
+ struct of_phandle_args args;
+ int ret;
+
+ pwrrdy = devm_kzalloc(dev, sizeof(*pwrrdy), GFP_KERNEL);
+ if (!pwrrdy)
+ return -ENOMEM;
+
+ ret = of_parse_phandle_with_args(dev->of_node, "renesas,sysc-signal",
+ "#renesas,sysc-signal-cells", 0, &args);
+ if (ret)
+ return ret;
+
+ pwrrdy->regmap = syscon_node_to_regmap(args.np);
+ pwrrdy->offset = args.args[0];
+ pwrrdy->mask = args.args[1];
+
+ of_node_put(args.np);
+
+ if (IS_ERR(pwrrdy->regmap))
+ return PTR_ERR(pwrrdy->regmap);
+
+ channel->pwrrdy = pwrrdy;
+
+ /* Power it ON. */
+ rcar_gen3_phy_usb2_set_pwrrdy(channel, true);
+
+ return devm_add_action_or_reset(dev, rcar_gen3_phy_usb2_pwrrdy_off, channel);
+}
+
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
{
const struct rcar_gen3_phy_drv_data *phy_data;
@@ -763,6 +823,12 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, channel);
channel->dev = dev;
+ if (phy_data->pwrrdy) {
+ ret = rcar_gen3_phy_usb2_init_pwrrdy(channel);
+ if (ret)
+ goto error;
+ }
+
if (phy_data->init_bus) {
ret = rcar_gen3_phy_usb2_init_bus(channel);
if (ret)
--
2.39.2
Powered by blists - more mailing lists