1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Renesas RZ/V2H(P) USB2PHY Port reset control driver 4 * 5 * Copyright (C) 2025 Renesas Electronics Corporation 6 */ 7 8 #include <linux/cleanup.h> 9 #include <linux/delay.h> 10 #include <linux/io.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/reset.h> 16 #include <linux/reset-controller.h> 17 18 struct rzv2h_usb2phy_regval { 19 u16 reg; 20 u16 val; 21 }; 22 23 struct rzv2h_usb2phy_reset_of_data { 24 const struct rzv2h_usb2phy_regval *init_vals; 25 unsigned int init_val_count; 26 27 u16 reset_reg; 28 u16 reset_assert_val; 29 u16 reset_deassert_val; 30 u16 reset_status_bits; 31 u16 reset_release_val; 32 33 u16 reset2_reg; 34 u16 reset2_acquire_val; 35 u16 reset2_release_val; 36 }; 37 38 struct rzv2h_usb2phy_reset_priv { 39 const struct rzv2h_usb2phy_reset_of_data *data; 40 void __iomem *base; 41 struct device *dev; 42 struct reset_controller_dev rcdev; 43 spinlock_t lock; /* protects register accesses */ 44 }; 45 46 static inline struct rzv2h_usb2phy_reset_priv 47 *rzv2h_usbphy_rcdev_to_priv(struct reset_controller_dev *rcdev) 48 { 49 return container_of(rcdev, struct rzv2h_usb2phy_reset_priv, rcdev); 50 } 51 52 /* This function must be called only after pm_runtime_resume_and_get() has been called */ 53 static void rzv2h_usbphy_assert_helper(struct rzv2h_usb2phy_reset_priv *priv) 54 { 55 const struct rzv2h_usb2phy_reset_of_data *data = priv->data; 56 57 scoped_guard(spinlock, &priv->lock) { 58 writel(data->reset2_acquire_val, priv->base + data->reset2_reg); 59 writel(data->reset_assert_val, priv->base + data->reset_reg); 60 } 61 62 usleep_range(11, 20); 63 } 64 65 static int rzv2h_usbphy_reset_assert(struct reset_controller_dev *rcdev, 66 unsigned long id) 67 { 68 struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev); 69 struct device *dev = priv->dev; 70 int ret; 71 72 ret = pm_runtime_resume_and_get(dev); 73 if (ret) { 74 dev_err(dev, "pm_runtime_resume_and_get failed\n"); 75 return ret; 76 } 77 78 rzv2h_usbphy_assert_helper(priv); 79 80 pm_runtime_put(dev); 81 82 return 0; 83 } 84 85 static int rzv2h_usbphy_reset_deassert(struct reset_controller_dev *rcdev, 86 unsigned long id) 87 { 88 struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev); 89 const struct rzv2h_usb2phy_reset_of_data *data = priv->data; 90 struct device *dev = priv->dev; 91 int ret; 92 93 ret = pm_runtime_resume_and_get(dev); 94 if (ret) { 95 dev_err(dev, "pm_runtime_resume_and_get failed\n"); 96 return ret; 97 } 98 99 scoped_guard(spinlock, &priv->lock) { 100 writel(data->reset_deassert_val, priv->base + data->reset_reg); 101 writel(data->reset2_release_val, priv->base + data->reset2_reg); 102 writel(data->reset_release_val, priv->base + data->reset_reg); 103 } 104 105 pm_runtime_put(dev); 106 107 return 0; 108 } 109 110 static int rzv2h_usbphy_reset_status(struct reset_controller_dev *rcdev, 111 unsigned long id) 112 { 113 struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev); 114 struct device *dev = priv->dev; 115 int ret; 116 u32 reg; 117 118 ret = pm_runtime_resume_and_get(dev); 119 if (ret) { 120 dev_err(dev, "pm_runtime_resume_and_get failed\n"); 121 return ret; 122 } 123 124 reg = readl(priv->base + priv->data->reset_reg); 125 126 pm_runtime_put(dev); 127 128 return (reg & priv->data->reset_status_bits) == priv->data->reset_status_bits; 129 } 130 131 static const struct reset_control_ops rzv2h_usbphy_reset_ops = { 132 .assert = rzv2h_usbphy_reset_assert, 133 .deassert = rzv2h_usbphy_reset_deassert, 134 .status = rzv2h_usbphy_reset_status, 135 }; 136 137 static int rzv2h_usb2phy_reset_of_xlate(struct reset_controller_dev *rcdev, 138 const struct of_phandle_args *reset_spec) 139 { 140 /* No special handling needed, we have only one reset line per device */ 141 return 0; 142 } 143 144 static int rzv2h_usb2phy_reset_probe(struct platform_device *pdev) 145 { 146 const struct rzv2h_usb2phy_reset_of_data *data; 147 struct rzv2h_usb2phy_reset_priv *priv; 148 struct device *dev = &pdev->dev; 149 struct reset_control *rstc; 150 int error; 151 152 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 153 if (!priv) 154 return -ENOMEM; 155 156 data = of_device_get_match_data(dev); 157 priv->data = data; 158 priv->dev = dev; 159 priv->base = devm_platform_ioremap_resource(pdev, 0); 160 if (IS_ERR(priv->base)) 161 return PTR_ERR(priv->base); 162 163 rstc = devm_reset_control_get_shared_deasserted(dev, NULL); 164 if (IS_ERR(rstc)) 165 return dev_err_probe(dev, PTR_ERR(rstc), 166 "failed to get deasserted reset\n"); 167 168 spin_lock_init(&priv->lock); 169 170 error = devm_pm_runtime_enable(dev); 171 if (error) 172 return dev_err_probe(dev, error, "Failed to enable pm_runtime\n"); 173 174 error = pm_runtime_resume_and_get(dev); 175 if (error) 176 return dev_err_probe(dev, error, "pm_runtime_resume_and_get failed\n"); 177 178 for (unsigned int i = 0; i < data->init_val_count; i++) 179 writel(data->init_vals[i].val, priv->base + data->init_vals[i].reg); 180 181 /* keep usb2phy in asserted state */ 182 rzv2h_usbphy_assert_helper(priv); 183 184 pm_runtime_put(dev); 185 186 priv->rcdev.ops = &rzv2h_usbphy_reset_ops; 187 priv->rcdev.of_reset_n_cells = 0; 188 priv->rcdev.nr_resets = 1; 189 priv->rcdev.of_xlate = rzv2h_usb2phy_reset_of_xlate; 190 priv->rcdev.of_node = dev->of_node; 191 priv->rcdev.dev = dev; 192 193 return devm_reset_controller_register(dev, &priv->rcdev); 194 } 195 196 /* 197 * initialization values required to prepare the PHY to receive 198 * assert and deassert requests. 199 */ 200 static const struct rzv2h_usb2phy_regval rzv2h_init_vals[] = { 201 { .reg = 0xc10, .val = 0x67c }, 202 { .reg = 0xc14, .val = 0x1f }, 203 { .reg = 0x600, .val = 0x909 }, 204 }; 205 206 static const struct rzv2h_usb2phy_reset_of_data rzv2h_reset_of_data = { 207 .init_vals = rzv2h_init_vals, 208 .init_val_count = ARRAY_SIZE(rzv2h_init_vals), 209 .reset_reg = 0, 210 .reset_assert_val = 0x206, 211 .reset_status_bits = BIT(2), 212 .reset_deassert_val = 0x200, 213 .reset_release_val = 0x0, 214 .reset2_reg = 0xb04, 215 .reset2_acquire_val = 0x303, 216 .reset2_release_val = 0x3, 217 }; 218 219 static const struct of_device_id rzv2h_usb2phy_reset_of_match[] = { 220 { .compatible = "renesas,r9a09g057-usb2phy-reset", .data = &rzv2h_reset_of_data }, 221 { /* Sentinel */ } 222 }; 223 MODULE_DEVICE_TABLE(of, rzv2h_usb2phy_reset_of_match); 224 225 static struct platform_driver rzv2h_usb2phy_reset_driver = { 226 .driver = { 227 .name = "rzv2h_usb2phy_reset", 228 .of_match_table = rzv2h_usb2phy_reset_of_match, 229 }, 230 .probe = rzv2h_usb2phy_reset_probe, 231 }; 232 module_platform_driver(rzv2h_usb2phy_reset_driver); 233 234 MODULE_LICENSE("GPL"); 235 MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); 236 MODULE_DESCRIPTION("Renesas RZ/V2H(P) USB2PHY Control"); 237