{
int ret;
- phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads");
- if (IS_ERR(phy->pad_clk)) {
- ret = PTR_ERR(phy->pad_clk);
- dev_err(phy->u_phy.dev,
- "Failed to get UTMIP pad clock: %d\n", ret);
- return ret;
- }
-
- phy->pad_rst = devm_reset_control_get_optional_shared(
- phy->u_phy.dev, "utmi-pads");
- if (IS_ERR(phy->pad_rst)) {
- ret = PTR_ERR(phy->pad_rst);
- dev_err(phy->u_phy.dev,
- "Failed to get UTMI-pads reset: %d\n", ret);
- return ret;
- }
-
ret = clk_prepare_enable(phy->pad_clk);
if (ret) {
dev_err(phy->u_phy.dev,
return 0;
}
-static void tegra_usb_phy_close(struct tegra_usb_phy *phy)
-{
- if (!IS_ERR(phy->vbus))
- regulator_disable(phy->vbus);
-
- if (!phy->is_ulpi_phy)
- utmip_pad_close(phy);
-
- clk_disable_unprepare(phy->pll_u);
-}
-
static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
{
int err;
return 0;
}
-static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
+static void tegra_usb_phy_shutdown(struct usb_phy *u_phy)
+{
+ struct tegra_usb_phy *phy = container_of(u_phy, struct tegra_usb_phy,
+ u_phy);
+
+ if (WARN_ON(!phy->freq))
+ return;
+
+ tegra_usb_phy_power_off(phy);
+
+ if (!phy->is_ulpi_phy)
+ utmip_pad_close(phy);
+
+ if (!IS_ERR(phy->vbus))
+ regulator_disable(phy->vbus);
+
+ clk_disable_unprepare(phy->pll_u);
+
+ phy->freq = NULL;
+}
+
+static int tegra_usb_phy_set_suspend(struct usb_phy *x, int suspend)
{
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+
+ if (WARN_ON(!phy->freq))
+ return -EINVAL;
+
if (suspend)
return tegra_usb_phy_power_off(phy);
else
{
int err;
- phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link");
- if (IS_ERR(phy->clk)) {
- err = PTR_ERR(phy->clk);
- dev_err(phy->u_phy.dev, "Failed to get ULPI clock: %d\n", err);
- return err;
- }
-
- err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio,
- "ulpi_phy_reset_b");
- if (err < 0) {
- dev_err(phy->u_phy.dev, "Request failed for GPIO %d: %d\n",
- phy->reset_gpio, err);
- return err;
- }
-
err = gpio_direction_output(phy->reset_gpio, 0);
if (err < 0) {
dev_err(phy->u_phy.dev,
- "GPIO %d direction not set to output: %d\n",
+ "ULPI reset GPIO %d direction not asserted: %d\n",
phy->reset_gpio, err);
return err;
}
- phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
- if (!phy->ulpi) {
- dev_err(phy->u_phy.dev, "Failed to create ULPI OTG\n");
- err = -ENOMEM;
- return err;
- }
-
- phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
return 0;
}
-static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
+static int tegra_usb_phy_init(struct usb_phy *u_phy)
{
+ struct tegra_usb_phy *phy = container_of(u_phy, struct tegra_usb_phy,
+ u_phy);
unsigned long parent_rate;
int i;
int err;
- phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u");
- if (IS_ERR(phy->pll_u)) {
- err = PTR_ERR(phy->pll_u);
- dev_err(phy->u_phy.dev,
- "Failed to get pll_u clock: %d\n", err);
- return err;
- }
+ if (WARN_ON(phy->freq))
+ return 0;
err = clk_prepare_enable(phy->pll_u);
if (err)
if (err < 0)
goto fail;
+ err = tegra_usb_phy_power_on(phy);
+ if (err)
+ goto close_phy;
+
return 0;
+close_phy:
+ if (!phy->is_ulpi_phy)
+ utmip_pad_close(phy);
fail:
clk_disable_unprepare(phy->pll_u);
+
+ phy->freq = NULL;
+
return err;
}
tegra_phy->vbus = ERR_PTR(-ENODEV);
}
- tegra_phy->u_phy.dev = &pdev->dev;
- err = tegra_usb_phy_init(tegra_phy);
- if (err < 0)
+ tegra_phy->pll_u = devm_clk_get(&pdev->dev, "pll_u");
+ err = PTR_ERR_OR_ZERO(tegra_phy->pll_u);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to get pll_u clock: %d\n", err);
return err;
+ }
+
+ if (tegra_phy->is_ulpi_phy) {
+ tegra_phy->clk = devm_clk_get(&pdev->dev, "ulpi-link");
+ err = PTR_ERR_OR_ZERO(tegra_phy->clk);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to get ULPI clock: %d\n", err);
+ return err;
+ }
- tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend;
+ err = devm_gpio_request(&pdev->dev, tegra_phy->reset_gpio,
+ "ulpi_phy_reset_b");
+ if (err < 0) {
+ dev_err(&pdev->dev, "Request failed for GPIO %d: %d\n",
+ tegra_phy->reset_gpio, err);
+ return err;
+ }
+
+ tegra_phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ if (!tegra_phy->ulpi) {
+ dev_err(&pdev->dev, "Failed to create ULPI OTG\n");
+ err = -ENOMEM;
+ return err;
+ }
+
+ tegra_phy->ulpi->io_priv = tegra_phy->regs + ULPI_VIEWPORT;
+ } else {
+ tegra_phy->pad_clk = devm_clk_get(&pdev->dev, "utmi-pads");
+ err = PTR_ERR_OR_ZERO(tegra_phy->pad_clk);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to get UTMIP pad clock: %d\n", err);
+ return err;
+ }
+
+ tegra_phy->pad_rst = devm_reset_control_get_optional_shared(
+ &pdev->dev, "utmi-pads");
+ err = PTR_ERR_OR_ZERO(tegra_phy->pad_rst);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to get UTMI-pads reset: %d\n", err);
+ return err;
+ }
+ }
+
+ tegra_phy->u_phy.dev = &pdev->dev;
+ tegra_phy->u_phy.init = tegra_usb_phy_init;
+ tegra_phy->u_phy.shutdown = tegra_usb_phy_shutdown;
+ tegra_phy->u_phy.set_suspend = tegra_usb_phy_set_suspend;
platform_set_drvdata(pdev, tegra_phy);
err = usb_add_phy_dev(&tegra_phy->u_phy);
- if (err < 0) {
- tegra_usb_phy_close(tegra_phy);
- return err;
- }
+ if (err < 0)
+ goto free_ulpi;
return 0;
+
+free_ulpi:
+ if (tegra_phy->ulpi) {
+ kfree(tegra_phy->ulpi->otg);
+ kfree(tegra_phy->ulpi);
+ }
+
+ return err;
}
static int tegra_usb_phy_remove(struct platform_device *pdev)
struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
usb_remove_phy(&tegra_phy->u_phy);
- tegra_usb_phy_close(tegra_phy);
+
+ if (tegra_phy->ulpi) {
+ kfree(tegra_phy->ulpi->otg);
+ kfree(tegra_phy->ulpi);
+ }
return 0;
}