diff options
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r-- | drivers/usb/renesas_usbhs/common.c | 113 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/common.h | 5 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/rcar3.c | 27 |
3 files changed, 110 insertions, 35 deletions
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 4310df46639d..a3e1290d682d 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -5,6 +5,7 @@ * Copyright (C) 2011 Renesas Solutions Corp. * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> */ +#include <linux/clk.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/io.h> @@ -12,6 +13,7 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/slab.h> #include <linux/sysfs.h> #include "common.h" @@ -290,6 +292,79 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv) usbhs_bset(priv, BUSWAIT, 0x000F, wait); } +static bool usbhsc_is_multi_clks(struct usbhs_priv *priv) +{ + if (priv->dparam.type == USBHS_TYPE_RCAR_GEN3 || + priv->dparam.type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) + return true; + + return false; +} + +static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv) +{ + if (!usbhsc_is_multi_clks(priv)) + return 0; + + /* The first clock should exist */ + priv->clks[0] = of_clk_get(dev->of_node, 0); + if (IS_ERR(priv->clks[0])) + return PTR_ERR(priv->clks[0]); + + /* + * To backward compatibility with old DT, this driver checks the return + * value if it's -ENOENT or not. + */ + priv->clks[1] = of_clk_get(dev->of_node, 1); + if (PTR_ERR(priv->clks[1]) == -ENOENT) + priv->clks[1] = NULL; + else if (IS_ERR(priv->clks[1])) + return PTR_ERR(priv->clks[1]); + + return 0; +} + +static void usbhsc_clk_put(struct usbhs_priv *priv) +{ + int i; + + if (!usbhsc_is_multi_clks(priv)) + return; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) + clk_put(priv->clks[i]); +} + +static int usbhsc_clk_prepare_enable(struct usbhs_priv *priv) +{ + int i, ret; + + if (!usbhsc_is_multi_clks(priv)) + return 0; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) { + ret = clk_prepare_enable(priv->clks[i]); + if (ret) { + while (--i >= 0) + clk_disable_unprepare(priv->clks[i]); + return ret; + } + } + + return ret; +} + +static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv) +{ + int i; + + if (!usbhsc_is_multi_clks(priv)) + return; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) + clk_disable_unprepare(priv->clks[i]); +} + /* * platform default param */ @@ -340,6 +415,10 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* enable PM */ pm_runtime_get_sync(dev); + /* enable clks */ + if (usbhsc_clk_prepare_enable(priv)) + return; + /* enable platform power */ usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); @@ -352,6 +431,9 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* disable platform power */ usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); + /* disable clks */ + usbhsc_clk_disable_unprepare(priv); + /* disable PM */ pm_runtime_put_sync(dev); } @@ -478,6 +560,10 @@ static const struct of_device_id usbhs_of_match[] = { .data = (void *)USBHS_TYPE_RCAR_GEN3, }, { + .compatible = "renesas,usbhs-r8a77990", + .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, + }, + { .compatible = "renesas,usbhs-r8a77995", .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, }, @@ -574,6 +660,10 @@ static int usbhs_probe(struct platform_device *pdev) return PTR_ERR(priv->edev); } + priv->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev); + if (IS_ERR(priv->rsts)) + return PTR_ERR(priv->rsts); + /* * care platform info */ @@ -591,15 +681,6 @@ static int usbhs_probe(struct platform_device *pdev) break; case USBHS_TYPE_RCAR_GEN3_WITH_PLL: priv->pfunc = usbhs_rcar3_with_pll_ops; - if (!IS_ERR_OR_NULL(priv->edev)) { - priv->nb.notifier_call = priv->pfunc.notifier; - ret = devm_extcon_register_notifier(&pdev->dev, - priv->edev, - EXTCON_USB_HOST, - &priv->nb); - if (ret < 0) - dev_err(&pdev->dev, "no notifier registered\n"); - } break; case USBHS_TYPE_RZA1: priv->pfunc = usbhs_rza1_ops; @@ -658,6 +739,14 @@ static int usbhs_probe(struct platform_device *pdev) /* dev_set_drvdata should be called after usbhs_mod_init */ platform_set_drvdata(pdev, priv); + ret = reset_control_deassert(priv->rsts); + if (ret) + goto probe_fail_rst; + + ret = usbhsc_clk_get(&pdev->dev, priv); + if (ret) + goto probe_fail_clks; + /* * deviece reset here because * USB device might be used in boot loader. @@ -711,6 +800,10 @@ static int usbhs_probe(struct platform_device *pdev) return ret; probe_end_mod_exit: + usbhsc_clk_put(priv); +probe_fail_clks: + reset_control_assert(priv->rsts); +probe_fail_rst: usbhs_mod_remove(priv); probe_end_fifo_exit: usbhs_fifo_remove(priv); @@ -739,6 +832,8 @@ static int usbhs_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usbhs_platform_call(priv, hardware_exit, pdev); + usbhsc_clk_put(priv); + reset_control_assert(priv->rsts); usbhs_mod_remove(priv); usbhs_fifo_remove(priv); usbhs_pipe_remove(priv); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 6137f7942c05..3777af848a35 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -8,8 +8,10 @@ #ifndef RENESAS_USB_DRIVER_H #define RENESAS_USB_DRIVER_H +#include <linux/clk.h> #include <linux/extcon.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/usb/renesas_usbhs.h> struct usbhs_priv; @@ -255,7 +257,6 @@ struct usbhs_priv { struct platform_device *pdev; struct extcon_dev *edev; - struct notifier_block nb; spinlock_t lock; @@ -277,6 +278,8 @@ struct usbhs_priv { struct usbhs_fifo_info fifo_info; struct phy *phy; + struct reset_control *rsts; + struct clk *clks[2]; }; /* diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index d0ea4ff89622..aa3820448286 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -27,7 +27,6 @@ * Remarks: bit[31:11] and bit[9:6] should be 0 */ #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ -#define UGCTRL2_USB0SEL_EHCI 0x00000010 #define UGCTRL2_USB0SEL_HSUSB 0x00000020 #define UGCTRL2_USB0SEL_OTG 0x00000030 #define UGCTRL2_VBUSSEL 0x00000400 @@ -50,14 +49,6 @@ static void usbhs_rcar3_set_ugctrl2(struct usbhs_priv *priv, u32 val) usbhs_write32(priv, UGCTRL2, val | UGCTRL2_RESERVED_3); } -static void usbhs_rcar3_set_usbsel(struct usbhs_priv *priv, bool ehci) -{ - if (ehci) - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_EHCI); - else - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); -} - static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, void __iomem *base, int enable) { @@ -83,14 +74,11 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev, struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); u32 val; int timeout = 1000; - bool is_host = false; if (enable) { usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */ - if (priv->edev) - is_host = extcon_get_state(priv->edev, EXTCON_USB_HOST); - - usbhs_rcar3_set_usbsel(priv, is_host); + usbhs_rcar3_set_ugctrl2(priv, + UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL); usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); do { @@ -112,16 +100,6 @@ static int usbhs_rcar3_get_id(struct platform_device *pdev) return USBHS_GADGET; } -static int usbhs_rcar3_notifier(struct notifier_block *nb, unsigned long event, - void *data) -{ - struct usbhs_priv *priv = container_of(nb, struct usbhs_priv, nb); - - usbhs_rcar3_set_usbsel(priv, !!event); - - return NOTIFY_DONE; -} - const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { .power_ctrl = usbhs_rcar3_power_ctrl, .get_id = usbhs_rcar3_get_id, @@ -130,5 +108,4 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = { .power_ctrl = usbhs_rcar3_power_and_pll_ctrl, .get_id = usbhs_rcar3_get_id, - .notifier = usbhs_rcar3_notifier, }; |