Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.18-rc2 236 lines 6.4 kB view raw
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 18struct rzv2h_usb2phy_regval { 19 u16 reg; 20 u16 val; 21}; 22 23struct 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 38struct 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 46static 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 */ 53static 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 65static 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 85static 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 110static 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 131static 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 137static 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 144static 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 */ 200static 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 206static 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 219static const struct of_device_id rzv2h_usb2phy_reset_of_match[] = { 220 { .compatible = "renesas,r9a09g057-usb2phy-reset", .data = &rzv2h_reset_of_data }, 221 { /* Sentinel */ } 222}; 223MODULE_DEVICE_TABLE(of, rzv2h_usb2phy_reset_of_match); 224 225static 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}; 232module_platform_driver(rzv2h_usb2phy_reset_driver); 233 234MODULE_LICENSE("GPL"); 235MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); 236MODULE_DESCRIPTION("Renesas RZ/V2H(P) USB2PHY Control");