summaryrefslogtreecommitdiff
path: root/drivers/reset/reset-rzg2l-usbphy-ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/reset/reset-rzg2l-usbphy-ctrl.c')
-rw-r--r--drivers/reset/reset-rzg2l-usbphy-ctrl.c63
1 files changed, 50 insertions, 13 deletions
diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
index a8dde4606360..255c894a4782 100644
--- a/drivers/reset/reset-rzg2l-usbphy-ctrl.c
+++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
@@ -10,10 +10,12 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/reset-controller.h>
#define RESET 0x000
+#define VBENCTL 0x03c
#define RESET_SEL_PLLRESET BIT(12)
#define RESET_PLLRESET BIT(8)
@@ -32,6 +34,7 @@ struct rzg2l_usbphy_ctrl_priv {
struct reset_controller_dev rcdev;
struct reset_control *rstc;
void __iomem *base;
+ struct platform_device *vdev;
spinlock_t lock;
};
@@ -100,10 +103,19 @@ static const struct reset_control_ops rzg2l_usbphy_ctrl_reset_ops = {
.status = rzg2l_usbphy_ctrl_status,
};
+static const struct regmap_config rzg2l_usb_regconf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 1,
+};
+
static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rzg2l_usbphy_ctrl_priv *priv;
+ struct platform_device *vdev;
+ struct regmap *regmap;
unsigned long flags;
int error;
u32 val;
@@ -116,6 +128,10 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
+ regmap = devm_regmap_init_mmio(dev, priv->base + VBENCTL, &rzg2l_usb_regconf);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(priv->rstc))
return dev_err_probe(dev, PTR_ERR(priv->rstc),
@@ -125,25 +141,14 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
if (error)
return error;
- priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops;
- priv->rcdev.of_reset_n_cells = 1;
- priv->rcdev.nr_resets = NUM_PORTS;
- priv->rcdev.of_node = dev->of_node;
- priv->rcdev.dev = dev;
-
- error = devm_reset_controller_register(dev, &priv->rcdev);
- if (error)
- return error;
-
spin_lock_init(&priv->lock);
dev_set_drvdata(dev, priv);
pm_runtime_enable(&pdev->dev);
error = pm_runtime_resume_and_get(&pdev->dev);
if (error < 0) {
- pm_runtime_disable(&pdev->dev);
- reset_control_assert(priv->rstc);
- return dev_err_probe(&pdev->dev, error, "pm_runtime_resume_and_get failed");
+ dev_err_probe(&pdev->dev, error, "pm_runtime_resume_and_get failed");
+ goto err_pm_disable_reset_deassert;
}
/* put pll and phy into reset state */
@@ -153,13 +158,45 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
writel(val, priv->base + RESET);
spin_unlock_irqrestore(&priv->lock, flags);
+ priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops;
+ priv->rcdev.of_reset_n_cells = 1;
+ priv->rcdev.nr_resets = NUM_PORTS;
+ priv->rcdev.of_node = dev->of_node;
+ priv->rcdev.dev = dev;
+
+ error = devm_reset_controller_register(dev, &priv->rcdev);
+ if (error)
+ goto err_pm_runtime_put;
+
+ vdev = platform_device_alloc("rzg2l-usb-vbus-regulator", pdev->id);
+ if (!vdev) {
+ error = -ENOMEM;
+ goto err_pm_runtime_put;
+ }
+ vdev->dev.parent = dev;
+ priv->vdev = vdev;
+
+ error = platform_device_add(vdev);
+ if (error)
+ goto err_device_put;
+
return 0;
+
+err_device_put:
+ platform_device_put(vdev);
+err_pm_runtime_put:
+ pm_runtime_put(&pdev->dev);
+err_pm_disable_reset_deassert:
+ pm_runtime_disable(&pdev->dev);
+ reset_control_assert(priv->rstc);
+ return error;
}
static int rzg2l_usbphy_ctrl_remove(struct platform_device *pdev)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_drvdata(&pdev->dev);
+ platform_device_unregister(priv->vdev);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
reset_control_assert(priv->rstc);