struct reset_control *rstc;
void __iomem *base;
struct platform_device *vdev;
+ struct regmap_field *pwrrdy;
spinlock_t lock;
};
return !!(readl(priv->base + RESET) & port_mask);
}
+/* put pll and phy into reset state */
+static void rzg2l_usbphy_ctrl_init(struct rzg2l_usbphy_ctrl_priv *priv)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ val = readl(priv->base + RESET);
+ val |= RESET_SEL_PLLRESET | RESET_PLLRESET | PHY_RESET_PORT2 | PHY_RESET_PORT1;
+ writel(val, priv->base + RESET);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
#define RZG2L_USBPHY_CTRL_PWRRDY 1
static const struct of_device_id rzg2l_usbphy_ctrl_match_table[] = {
rzg2l_usbphy_ctrl_set_pwrrdy(data, false);
}
-static int rzg2l_usbphy_ctrl_pwrrdy_init(struct device *dev)
+static int rzg2l_usbphy_ctrl_pwrrdy_init(struct device *dev,
+ struct rzg2l_usbphy_ctrl_priv *priv)
{
- struct regmap_field *pwrrdy;
struct reg_field field;
struct regmap *regmap;
const int *data;
field.lsb = __ffs(args[1]);
field.msb = __fls(args[1]);
- pwrrdy = devm_regmap_field_alloc(dev, regmap, field);
- if (IS_ERR(pwrrdy))
- return PTR_ERR(pwrrdy);
+ priv->pwrrdy = devm_regmap_field_alloc(dev, regmap, field);
+ if (IS_ERR(priv->pwrrdy))
+ return PTR_ERR(priv->pwrrdy);
ret = rzg2l_usbphy_ctrl_set_pwrrdy(priv->pwrrdy, true);
if (ret)
return ret;
- return devm_add_action_or_reset(dev, rzg2l_usbphy_ctrl_pwrrdy_off, pwrrdy);
+ return devm_add_action_or_reset(dev, rzg2l_usbphy_ctrl_pwrrdy_off, priv->pwrrdy);
}
static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
struct rzg2l_usbphy_ctrl_priv *priv;
struct platform_device *vdev;
struct regmap *regmap;
- unsigned long flags;
int error;
- u32 val;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- error = rzg2l_usbphy_ctrl_pwrrdy_init(dev);
+ error = rzg2l_usbphy_ctrl_pwrrdy_init(dev, priv);
if (error)
return error;
goto err_pm_disable_reset_deassert;
}
- /* put pll and phy into reset state */
- spin_lock_irqsave(&priv->lock, flags);
- val = readl(priv->base + RESET);
- val |= RESET_SEL_PLLRESET | RESET_PLLRESET | PHY_RESET_PORT2 | PHY_RESET_PORT1;
- writel(val, priv->base + RESET);
- spin_unlock_irqrestore(&priv->lock, flags);
+ rzg2l_usbphy_ctrl_init(priv);
priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops;
priv->rcdev.of_reset_n_cells = 1;
reset_control_assert(priv->rstc);
}
+static int rzg2l_usbphy_ctrl_suspend(struct device *dev)
+{
+ struct rzg2l_usbphy_ctrl_priv *priv = dev_get_drvdata(dev);
+ u32 val;
+ int ret;
+
+ val = readl(priv->base + RESET);
+ if (!(val & PHY_RESET_PORT2) || !(val & PHY_RESET_PORT1))
+ WARN(1, "Suspend with resets de-asserted\n");
+
+ pm_runtime_put_sync(dev);
+
+ ret = reset_control_assert(priv->rstc);
+ if (ret)
+ goto rpm_resume;
+
+ ret = rzg2l_usbphy_ctrl_set_pwrrdy(priv->pwrrdy, false);
+ if (ret)
+ goto reset_deassert;
+
+ return 0;
+
+reset_deassert:
+ reset_control_deassert(priv->rstc);
+rpm_resume:
+ pm_runtime_resume_and_get(dev);
+ return ret;
+}
+
+static int rzg2l_usbphy_ctrl_resume(struct device *dev)
+{
+ struct rzg2l_usbphy_ctrl_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = rzg2l_usbphy_ctrl_set_pwrrdy(priv->pwrrdy, true);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(priv->rstc);
+ if (ret)
+ goto pwrrdy_off;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ goto reset_assert;
+
+ rzg2l_usbphy_ctrl_init(priv);
+
+ return 0;
+
+reset_assert:
+ reset_control_assert(priv->rstc);
+pwrrdy_off:
+ rzg2l_usbphy_ctrl_set_pwrrdy(priv->pwrrdy, false);
+ return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rzg2l_usbphy_ctrl_pm_ops,
+ rzg2l_usbphy_ctrl_suspend,
+ rzg2l_usbphy_ctrl_resume);
+
static struct platform_driver rzg2l_usbphy_ctrl_driver = {
.driver = {
.name = "rzg2l_usbphy_ctrl",
.of_match_table = rzg2l_usbphy_ctrl_match_table,
+ .pm = pm_ptr(&rzg2l_usbphy_ctrl_pm_ops),
},
.probe = rzg2l_usbphy_ctrl_probe,
.remove = rzg2l_usbphy_ctrl_remove,