reset-rzg2l-usbphy-ctrl.c (4790B)
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/reset.h> 14#include <linux/reset-controller.h> 15 16#define RESET 0x000 17 18#define RESET_SEL_PLLRESET BIT(12) 19#define RESET_PLLRESET BIT(8) 20 21#define RESET_SEL_P2RESET BIT(5) 22#define RESET_SEL_P1RESET BIT(4) 23#define RESET_PHYRST_2 BIT(1) 24#define RESET_PHYRST_1 BIT(0) 25 26#define PHY_RESET_PORT2 (RESET_SEL_P2RESET | RESET_PHYRST_2) 27#define PHY_RESET_PORT1 (RESET_SEL_P1RESET | RESET_PHYRST_1) 28 29#define NUM_PORTS 2 30 31struct rzg2l_usbphy_ctrl_priv { 32 struct reset_controller_dev rcdev; 33 struct reset_control *rstc; 34 void __iomem *base; 35 36 spinlock_t lock; 37}; 38 39#define rcdev_to_priv(x) container_of(x, struct rzg2l_usbphy_ctrl_priv, rcdev) 40 41static int rzg2l_usbphy_ctrl_assert(struct reset_controller_dev *rcdev, 42 unsigned long id) 43{ 44 struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev); 45 u32 port_mask = PHY_RESET_PORT1 | PHY_RESET_PORT2; 46 void __iomem *base = priv->base; 47 unsigned long flags; 48 u32 val; 49 50 spin_lock_irqsave(&priv->lock, flags); 51 val = readl(base + RESET); 52 val |= id ? PHY_RESET_PORT2 : PHY_RESET_PORT1; 53 if (port_mask == (val & port_mask)) 54 val |= RESET_PLLRESET; 55 writel(val, base + RESET); 56 spin_unlock_irqrestore(&priv->lock, flags); 57 58 return 0; 59} 60 61static int rzg2l_usbphy_ctrl_deassert(struct reset_controller_dev *rcdev, 62 unsigned long id) 63{ 64 struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev); 65 void __iomem *base = priv->base; 66 unsigned long flags; 67 u32 val; 68 69 spin_lock_irqsave(&priv->lock, flags); 70 val = readl(base + RESET); 71 72 val |= RESET_SEL_PLLRESET; 73 val &= ~(RESET_PLLRESET | (id ? PHY_RESET_PORT2 : PHY_RESET_PORT1)); 74 writel(val, base + RESET); 75 spin_unlock_irqrestore(&priv->lock, flags); 76 77 return 0; 78} 79 80static int rzg2l_usbphy_ctrl_status(struct reset_controller_dev *rcdev, 81 unsigned long id) 82{ 83 struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev); 84 u32 port_mask; 85 86 port_mask = id ? PHY_RESET_PORT2 : PHY_RESET_PORT1; 87 88 return !!(readl(priv->base + RESET) & port_mask); 89} 90 91static const struct of_device_id rzg2l_usbphy_ctrl_match_table[] = { 92 { .compatible = "renesas,rzg2l-usbphy-ctrl" }, 93 { /* Sentinel */ } 94}; 95MODULE_DEVICE_TABLE(of, rzg2l_usbphy_ctrl_match_table); 96 97static const struct reset_control_ops rzg2l_usbphy_ctrl_reset_ops = { 98 .assert = rzg2l_usbphy_ctrl_assert, 99 .deassert = rzg2l_usbphy_ctrl_deassert, 100 .status = rzg2l_usbphy_ctrl_status, 101}; 102 103static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev) 104{ 105 struct device *dev = &pdev->dev; 106 struct rzg2l_usbphy_ctrl_priv *priv; 107 unsigned long flags; 108 int error; 109 u32 val; 110 111 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 112 if (!priv) 113 return -ENOMEM; 114 115 priv->base = devm_platform_ioremap_resource(pdev, 0); 116 if (IS_ERR(priv->base)) 117 return PTR_ERR(priv->base); 118 119 priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); 120 if (IS_ERR(priv->rstc)) 121 return dev_err_probe(dev, PTR_ERR(priv->rstc), 122 "failed to get reset\n"); 123 124 error = reset_control_deassert(priv->rstc); 125 if (error) 126 return error; 127 128 priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops; 129 priv->rcdev.of_reset_n_cells = 1; 130 priv->rcdev.nr_resets = NUM_PORTS; 131 priv->rcdev.of_node = dev->of_node; 132 priv->rcdev.dev = dev; 133 134 error = devm_reset_controller_register(dev, &priv->rcdev); 135 if (error) 136 return error; 137 138 spin_lock_init(&priv->lock); 139 dev_set_drvdata(dev, priv); 140 141 pm_runtime_enable(&pdev->dev); 142 error = pm_runtime_resume_and_get(&pdev->dev); 143 if (error < 0) { 144 pm_runtime_disable(&pdev->dev); 145 reset_control_assert(priv->rstc); 146 return dev_err_probe(&pdev->dev, error, "pm_runtime_resume_and_get failed"); 147 } 148 149 /* put pll and phy into reset state */ 150 spin_lock_irqsave(&priv->lock, flags); 151 val = readl(priv->base + RESET); 152 val |= RESET_SEL_PLLRESET | RESET_PLLRESET | PHY_RESET_PORT2 | PHY_RESET_PORT1; 153 writel(val, priv->base + RESET); 154 spin_unlock_irqrestore(&priv->lock, flags); 155 156 return 0; 157} 158 159static int rzg2l_usbphy_ctrl_remove(struct platform_device *pdev) 160{ 161 struct rzg2l_usbphy_ctrl_priv *priv = dev_get_drvdata(&pdev->dev); 162 163 pm_runtime_put(&pdev->dev); 164 pm_runtime_disable(&pdev->dev); 165 reset_control_assert(priv->rstc); 166 167 return 0; 168} 169 170static struct platform_driver rzg2l_usbphy_ctrl_driver = { 171 .driver = { 172 .name = "rzg2l_usbphy_ctrl", 173 .of_match_table = rzg2l_usbphy_ctrl_match_table, 174 }, 175 .probe = rzg2l_usbphy_ctrl_probe, 176 .remove = rzg2l_usbphy_ctrl_remove, 177}; 178module_platform_driver(rzg2l_usbphy_ctrl_driver); 179 180MODULE_LICENSE("GPL v2"); 181MODULE_DESCRIPTION("Renesas RZ/G2L USBPHY Control"); 182MODULE_AUTHOR("biju.das.jz@bp.renesas.com>");