summaryrefslogtreecommitdiff
path: root/drivers/usb/renesas_usbhs/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/renesas_usbhs/common.c')
-rw-r--r--drivers/usb/renesas_usbhs/common.c105
1 files changed, 73 insertions, 32 deletions
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index dd1c17542439..f52418fe3fd4 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -312,8 +312,10 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
priv->clks[1] = of_clk_get(dev_of_node(dev), 1);
if (PTR_ERR(priv->clks[1]) == -ENOENT)
priv->clks[1] = NULL;
- else if (IS_ERR(priv->clks[1]))
+ else if (IS_ERR(priv->clks[1])) {
+ clk_put(priv->clks[0]);
return PTR_ERR(priv->clks[1]);
+ }
return 0;
}
@@ -363,14 +365,14 @@ static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv)
* platform default param
*/
-/* commonly used on old SH-Mobile SoCs */
+/* commonly used on old SH-Mobile and RZ/G2L family SoCs */
static struct renesas_usbhs_driver_pipe_config usbhsc_default_pipe[] = {
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_CONTROL, 64, 0x00, false),
- RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, false),
- RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x18, false),
- RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x28, true),
- RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x38, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x28, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x48, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x58, true),
+ RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x68, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x04, false),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x05, false),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x06, false),
@@ -566,6 +568,18 @@ static const struct of_device_id usbhs_of_match[] = {
.data = &usbhs_rcar_gen3_with_pll_plat_info,
},
{
+ .compatible = "renesas,usbhs-r9a07g043",
+ .data = &usbhs_rzg2l_plat_info,
+ },
+ {
+ .compatible = "renesas,usbhs-r9a07g044",
+ .data = &usbhs_rzg2l_plat_info,
+ },
+ {
+ .compatible = "renesas,usbhs-r9a07g054",
+ .data = &usbhs_rzg2l_plat_info,
+ },
+ {
.compatible = "renesas,rcar-gen2-usbhs",
.data = &usbhs_rcar_gen2_plat_info,
},
@@ -581,7 +595,11 @@ static const struct of_device_id usbhs_of_match[] = {
.compatible = "renesas,rza2-usbhs",
.data = &usbhs_rza2_plat_info,
},
- { },
+ {
+ .compatible = "renesas,rzg2l-usbhs",
+ .data = &usbhs_rzg2l_plat_info,
+ },
+ { }
};
MODULE_DEVICE_TABLE(of, usbhs_of_match);
@@ -595,16 +613,11 @@ static int usbhs_probe(struct platform_device *pdev)
u32 tmp;
int irq;
- /* check device node */
- if (dev_of_node(dev))
- info = of_device_get_match_data(dev);
- else
- info = renesas_usbhs_get_info(pdev);
-
- /* check platform information */
+ info = of_device_get_match_data(dev);
if (!info) {
- dev_err(dev, "no platform information\n");
- return -EINVAL;
+ info = dev_get_platdata(dev);
+ if (!info)
+ return dev_err_probe(dev, -EINVAL, "no platform info\n");
}
/* platform data */
@@ -621,7 +634,7 @@ static int usbhs_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- if (of_property_read_bool(dev_of_node(dev), "extcon")) {
+ if (of_property_present(dev_of_node(dev), "extcon")) {
priv->edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(priv->edev))
return PTR_ERR(priv->edev);
@@ -672,10 +685,29 @@ static int usbhs_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug);
spin_lock_init(usbhs_priv_to_lock(priv));
+ /*
+ * Acquire clocks and enable power management (PM) early in the
+ * probe process, as the driver accesses registers during
+ * initialization. Ensure the device is active before proceeding.
+ */
+ pm_runtime_enable(dev);
+
+ ret = usbhsc_clk_get(dev, priv);
+ if (ret)
+ goto probe_pm_disable;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ goto probe_clk_put;
+
+ ret = usbhsc_clk_prepare_enable(priv);
+ if (ret)
+ goto probe_pm_put;
+
/* call pipe and module init */
ret = usbhs_pipe_probe(priv);
if (ret < 0)
- return ret;
+ goto probe_clk_dis_unprepare;
ret = usbhs_fifo_probe(priv);
if (ret < 0)
@@ -685,19 +717,15 @@ static int usbhs_probe(struct platform_device *pdev)
if (ret < 0)
goto probe_end_fifo_exit;
- /* dev_set_drvdata should be called after usbhs_mod_init */
+ /* platform_set_drvdata() should be called after usbhs_mod_probe() */
platform_set_drvdata(pdev, priv);
ret = reset_control_deassert(priv->rsts);
if (ret)
goto probe_fail_rst;
- ret = usbhsc_clk_get(dev, priv);
- if (ret)
- goto probe_fail_clks;
-
/*
- * deviece reset here because
+ * device reset here because
* USB device might be used in boot loader.
*/
usbhs_sys_clock_ctrl(priv, 0);
@@ -708,7 +736,7 @@ static int usbhs_probe(struct platform_device *pdev)
if (ret) {
dev_warn(dev, "USB function not selected (GPIO)\n");
ret = -ENOTSUPP;
- goto probe_end_mod_exit;
+ goto probe_assert_rest;
}
}
@@ -722,14 +750,19 @@ static int usbhs_probe(struct platform_device *pdev)
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
dev_err(dev, "platform init failed.\n");
- goto probe_end_mod_exit;
+ goto probe_assert_rest;
}
/* reset phy for connection */
usbhs_platform_call(priv, phy_reset, pdev);
- /* power control */
- pm_runtime_enable(dev);
+ /*
+ * Disable the clocks that were enabled earlier in the probe path,
+ * and let the driver handle the clocks beyond this point.
+ */
+ usbhsc_clk_disable_unprepare(priv);
+ pm_runtime_put(dev);
+
if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
usbhsc_power_ctrl(priv, 1);
usbhs_mod_autonomy_mode(priv);
@@ -746,9 +779,7 @@ static int usbhs_probe(struct platform_device *pdev)
return ret;
-probe_end_mod_exit:
- usbhsc_clk_put(priv);
-probe_fail_clks:
+probe_assert_rest:
reset_control_assert(priv->rsts);
probe_fail_rst:
usbhs_mod_remove(priv);
@@ -756,6 +787,14 @@ probe_end_fifo_exit:
usbhs_fifo_remove(priv);
probe_end_pipe_exit:
usbhs_pipe_remove(priv);
+probe_clk_dis_unprepare:
+ usbhsc_clk_disable_unprepare(priv);
+probe_pm_put:
+ pm_runtime_put(dev);
+probe_clk_put:
+ usbhsc_clk_put(priv);
+probe_pm_disable:
+ pm_runtime_disable(dev);
dev_info(dev, "probe failed (%d)\n", ret);
@@ -768,6 +807,8 @@ static void usbhs_remove(struct platform_device *pdev)
dev_dbg(&pdev->dev, "usb remove\n");
+ flush_delayed_work(&priv->notify_hotplug_work);
+
/* power off */
if (!usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, 0);
@@ -824,7 +865,7 @@ static struct platform_driver renesas_usbhs_driver = {
.of_match_table = usbhs_of_match,
},
.probe = usbhs_probe,
- .remove_new = usbhs_remove,
+ .remove = usbhs_remove,
};
module_platform_driver(renesas_usbhs_driver);