File Index
Files and directories
Sign in
FILE

reset-rzg2l-usbphy-ctrl.c

File preview with syntax highlighting.

linux-6.19.14/drivers/reset/reset-rzg2l-usbphy-ctrl.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Renesas RZ/G2L USBPHY control driver
  4 *
  5 * Copyright (C) 2021 Renesas Electronics Corporation
  6 */
  7
  8#include <linux/io.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 11#include <linux/platform_device.h>
 12#include <linux/pm_runtime.h>
 13#include <linux/regmap.h>
 14#include <linux/reset.h>
 15#include <linux/reset-controller.h>
 16#include <linux/mfd/syscon.h>
 17
 18#define RESET			0x000
 19#define VBENCTL			0x03c
 20
 21#define RESET_SEL_PLLRESET	BIT(12)
 22#define RESET_PLLRESET		BIT(8)
 23
 24#define RESET_SEL_P2RESET	BIT(5)
 25#define RESET_SEL_P1RESET	BIT(4)
 26#define RESET_PHYRST_2		BIT(1)
 27#define RESET_PHYRST_1		BIT(0)
 28
 29#define PHY_RESET_PORT2		(RESET_SEL_P2RESET | RESET_PHYRST_2)
 30#define PHY_RESET_PORT1		(RESET_SEL_P1RESET | RESET_PHYRST_1)
 31
 32#define NUM_PORTS		2
 33
 34struct rzg2l_usbphy_ctrl_priv {
 35	struct reset_controller_dev rcdev;
 36	struct reset_control *rstc;
 37	void __iomem *base;
 38	struct platform_device *vdev;
 39
 40	spinlock_t lock;
 41};
 42
 43#define rcdev_to_priv(x)	container_of(x, struct rzg2l_usbphy_ctrl_priv, rcdev)
 44
 45static int rzg2l_usbphy_ctrl_assert(struct reset_controller_dev *rcdev,
 46				    unsigned long id)
 47{
 48	struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev);
 49	u32 port_mask = PHY_RESET_PORT1 | PHY_RESET_PORT2;
 50	void __iomem *base = priv->base;
 51	unsigned long flags;
 52	u32 val;
 53
 54	spin_lock_irqsave(&priv->lock, flags);
 55	val = readl(base + RESET);
 56	val |= id ? PHY_RESET_PORT2 : PHY_RESET_PORT1;
 57	if (port_mask == (val & port_mask))
 58		val |= RESET_PLLRESET;
 59	writel(val, base + RESET);
 60	spin_unlock_irqrestore(&priv->lock, flags);
 61
 62	return 0;
 63}
 64
 65static int rzg2l_usbphy_ctrl_deassert(struct reset_controller_dev *rcdev,
 66				      unsigned long id)
 67{
 68	struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev);
 69	void __iomem *base = priv->base;
 70	unsigned long flags;
 71	u32 val;
 72
 73	spin_lock_irqsave(&priv->lock, flags);
 74	val = readl(base + RESET);
 75
 76	val |= RESET_SEL_PLLRESET;
 77	val &= ~(RESET_PLLRESET | (id ? PHY_RESET_PORT2 : PHY_RESET_PORT1));
 78	writel(val, base + RESET);
 79	spin_unlock_irqrestore(&priv->lock, flags);
 80
 81	return 0;
 82}
 83
 84static int rzg2l_usbphy_ctrl_status(struct reset_controller_dev *rcdev,
 85				    unsigned long id)
 86{
 87	struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev);
 88	u32 port_mask;
 89
 90	port_mask = id ? PHY_RESET_PORT2 : PHY_RESET_PORT1;
 91
 92	return !!(readl(priv->base + RESET) & port_mask);
 93}
 94
 95#define RZG2L_USBPHY_CTRL_PWRRDY	1
 96
 97static const struct of_device_id rzg2l_usbphy_ctrl_match_table[] = {
 98	{ .compatible = "renesas,rzg2l-usbphy-ctrl" },
 99	{
100		.compatible = "renesas,r9a08g045-usbphy-ctrl",
101		.data = (void *)RZG2L_USBPHY_CTRL_PWRRDY
102	},
103	{ /* Sentinel */ }
104};
105MODULE_DEVICE_TABLE(of, rzg2l_usbphy_ctrl_match_table);
106
107static const struct reset_control_ops rzg2l_usbphy_ctrl_reset_ops = {
108	.assert = rzg2l_usbphy_ctrl_assert,
109	.deassert = rzg2l_usbphy_ctrl_deassert,
110	.status = rzg2l_usbphy_ctrl_status,
111};
112
113static const struct regmap_config rzg2l_usb_regconf = {
114	.reg_bits = 32,
115	.val_bits = 32,
116	.reg_stride = 4,
117	.max_register = 1,
118};
119
120static void rzg2l_usbphy_ctrl_set_pwrrdy(struct regmap_field *pwrrdy,
121					 bool power_on)
122{
123	u32 val = power_on ? 0 : 1;
124
125	/* The initialization path guarantees that the mask is 1 bit long. */
126	regmap_field_update_bits(pwrrdy, 1, val);
127}
128
129static void rzg2l_usbphy_ctrl_pwrrdy_off(void *data)
130{
131	rzg2l_usbphy_ctrl_set_pwrrdy(data, false);
132}
133
134static int rzg2l_usbphy_ctrl_pwrrdy_init(struct device *dev)
135{
136	struct regmap_field *pwrrdy;
137	struct reg_field field;
138	struct regmap *regmap;
139	const int *data;
140	u32 args[2];
141
142	data = device_get_match_data(dev);
143	if ((uintptr_t)data != RZG2L_USBPHY_CTRL_PWRRDY)
144		return 0;
145
146	regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
147						      "renesas,sysc-pwrrdy",
148						      ARRAY_SIZE(args), args);
149	if (IS_ERR(regmap))
150		return PTR_ERR(regmap);
151
152	/* Don't allow more than one bit in mask. */
153	if (hweight32(args[1]) != 1)
154		return -EINVAL;
155
156	field.reg = args[0];
157	field.lsb = __ffs(args[1]);
158	field.msb = __fls(args[1]);
159
160	pwrrdy = devm_regmap_field_alloc(dev, regmap, field);
161	if (IS_ERR(pwrrdy))
162		return PTR_ERR(pwrrdy);
163
164	rzg2l_usbphy_ctrl_set_pwrrdy(pwrrdy, true);
165
166	return devm_add_action_or_reset(dev, rzg2l_usbphy_ctrl_pwrrdy_off, pwrrdy);
167}
168
169static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
170{
171	struct device *dev = &pdev->dev;
172	struct rzg2l_usbphy_ctrl_priv *priv;
173	struct platform_device *vdev;
174	struct regmap *regmap;
175	unsigned long flags;
176	int error;
177	u32 val;
178
179	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
180	if (!priv)
181		return -ENOMEM;
182
183	priv->base = devm_platform_ioremap_resource(pdev, 0);
184	if (IS_ERR(priv->base))
185		return PTR_ERR(priv->base);
186
187	regmap = devm_regmap_init_mmio(dev, priv->base + VBENCTL, &rzg2l_usb_regconf);
188	if (IS_ERR(regmap))
189		return PTR_ERR(regmap);
190
191	error = rzg2l_usbphy_ctrl_pwrrdy_init(dev);
192	if (error)
193		return error;
194
195	priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
196	if (IS_ERR(priv->rstc))
197		return dev_err_probe(dev, PTR_ERR(priv->rstc),
198				     "failed to get reset\n");
199
200	error = reset_control_deassert(priv->rstc);
201	if (error)
202		return error;
203
204	spin_lock_init(&priv->lock);
205	dev_set_drvdata(dev, priv);
206
207	pm_runtime_enable(&pdev->dev);
208	error = pm_runtime_resume_and_get(&pdev->dev);
209	if (error < 0) {
210		dev_err_probe(&pdev->dev, error, "pm_runtime_resume_and_get failed");
211		goto err_pm_disable_reset_deassert;
212	}
213
214	/* put pll and phy into reset state */
215	spin_lock_irqsave(&priv->lock, flags);
216	val = readl(priv->base + RESET);
217	val |= RESET_SEL_PLLRESET | RESET_PLLRESET | PHY_RESET_PORT2 | PHY_RESET_PORT1;
218	writel(val, priv->base + RESET);
219	spin_unlock_irqrestore(&priv->lock, flags);
220
221	priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops;
222	priv->rcdev.of_reset_n_cells = 1;
223	priv->rcdev.nr_resets = NUM_PORTS;
224	priv->rcdev.of_node = dev->of_node;
225	priv->rcdev.dev = dev;
226
227	error = devm_reset_controller_register(dev, &priv->rcdev);
228	if (error)
229		goto err_pm_runtime_put;
230
231	vdev = platform_device_alloc("rzg2l-usb-vbus-regulator", pdev->id);
232	if (!vdev) {
233		error = -ENOMEM;
234		goto err_pm_runtime_put;
235	}
236	vdev->dev.parent = dev;
237	priv->vdev = vdev;
238
239	device_set_of_node_from_dev(&vdev->dev, dev);
240	error = platform_device_add(vdev);
241	if (error)
242		goto err_device_put;
243
244	return 0;
245
246err_device_put:
247	platform_device_put(vdev);
248err_pm_runtime_put:
249	pm_runtime_put(&pdev->dev);
250err_pm_disable_reset_deassert:
251	pm_runtime_disable(&pdev->dev);
252	reset_control_assert(priv->rstc);
253	return error;
254}
255
256static void rzg2l_usbphy_ctrl_remove(struct platform_device *pdev)
257{
258	struct rzg2l_usbphy_ctrl_priv *priv = dev_get_drvdata(&pdev->dev);
259
260	platform_device_unregister(priv->vdev);
261	pm_runtime_put(&pdev->dev);
262	pm_runtime_disable(&pdev->dev);
263	reset_control_assert(priv->rstc);
264}
265
266static struct platform_driver rzg2l_usbphy_ctrl_driver = {
267	.driver = {
268		.name		= "rzg2l_usbphy_ctrl",
269		.of_match_table	= rzg2l_usbphy_ctrl_match_table,
270	},
271	.probe	= rzg2l_usbphy_ctrl_probe,
272	.remove = rzg2l_usbphy_ctrl_remove,
273};
274module_platform_driver(rzg2l_usbphy_ctrl_driver);
275
276MODULE_LICENSE("GPL v2");
277MODULE_DESCRIPTION("Renesas RZ/G2L USBPHY Control");
278MODULE_AUTHOR("biju.das.jz@bp.renesas.com>");
~/ Read-only file preview.