Commit ceca718f authored by Olof Johansson's avatar Olof Johansson

Merge tag 'tegra-for-3.9-soc-usb' of...

Merge tag 'tegra-for-3.9-soc-usb' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra into next/soc

From Stephen Warren:
ARM: tegra: USB driver cleanup

The Tegra USB driver has a number of issues:

1) The PHY driver isn't a true platform device, and doesn't implement
   the standard USB PHY API.

2) struct device instance numbers were used to make decisions in the
   driver, rather than being parameterized by DT or platform data.

This pull request solves issue (2), and lays the groundwork for solving
issue (1). The work on issue (1) involved introducing new DT nodes for
the USB PHYs, which in turn interacted with the Tegra common clock
framework changes, due to the move of clock lookups into device tree.
Hence, these USB driver changes are taken through the Tegra tree with
acks from USB maintainers.

This pull request is based on the previous pull request, with tag
tegra-for-3.9-soc-ccf.

* tag 'tegra-for-3.9-soc-usb' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra:
  usb: host: tegra: make use of PHY pointer of HCD
  ARM: tegra: Add reset GPIO information to PHY DT node
  usb: host: tegra: don't touch EMC clock
  usb: add APIs to access host registers from Tegra PHY
  USB: PHY: tegra: Get rid of instance number to differentiate PHY type
  USB: PHY: tegra: get rid of instance number to differentiate legacy controller
  ARM: tegra: add clocks properties to USB PHY nodes
  ARM: tegra: add DT nodes for Tegra USB PHY
  usb: phy: remove unused APIs from Tegra PHY.
  usb: host: tegra: Resetting PORT0 based on information received via DT.
  ARM: tegra: Add new DT property to USB node.
  usb: phy: use kzalloc to allocate struct tegra_usb_phy
  ARM: tegra: remove USB address related macros from iomap.h
parents bda6f8e6 ab137d04
......@@ -11,6 +11,7 @@ Required properties :
- phy_type : Should be one of "ulpi" or "utmi".
- nvidia,vbus-gpio : If present, specifies a gpio that needs to be
activated for the bus to be powered.
- nvidia,phy : phandle of the PHY instance, the controller is connected to.
Required properties for phy_type == ulpi:
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
......@@ -27,3 +28,5 @@ Optional properties:
registers are accessed through the APB_MISC base address instead of
the USB controller. Since this is a legacy issue it probably does not
warrant a compatible string of its own.
- nvidia,needs-double-reset : boolean is to be set for some of the Tegra2
USB ports, which need reset twice due to hardware issues.
Tegra SOC USB PHY
The device node for Tegra SOC USB PHY:
Required properties :
- compatible : Should be "nvidia,tegra20-usb-phy".
- reg : Address and length of the register set for the USB PHY interface.
- phy_type : Should be one of "ulpi" or "utmi".
Required properties for phy_type == ulpi:
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
Optional properties:
- nvidia,has-legacy-mode : boolean indicates whether this controller can
operate in legacy mode (as APX 2500 / 2600). In legacy mode some
registers are accessed through the APB_MISC base address instead of
the USB controller.
\ No newline at end of file
......@@ -432,6 +432,10 @@ usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
};
sdhci@c8000200 {
status = "okay";
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
......
......@@ -420,6 +420,10 @@ usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
};
sdhci@c8000000 {
status = "okay";
cd-gpios = <&gpio 173 0>; /* gpio PV5 */
......
......@@ -561,6 +561,10 @@ usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
};
sdhci@c8000000 {
status = "okay";
power-gpios = <&gpio 86 0>; /* gpio PK6 */
......
......@@ -310,6 +310,10 @@ usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
};
sdhci@c8000000 {
status = "okay";
bus-width = <4>;
......
......@@ -497,6 +497,10 @@ usb@c5008000 {
status = "okay";
};
usb-phy@c5004400 {
nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
};
sdhci@c8000000 {
status = "okay";
power-gpios = <&gpio 86 0>; /* gpio PK6 */
......
......@@ -400,6 +400,31 @@ memory-controller@7000f400 {
#size-cells = <0>;
};
phy1: usb-phy@c5000400 {
compatible = "nvidia,tegra20-usb-phy";
reg = <0xc5000400 0x3c00>;
phy_type = "utmi";
nvidia,has-legacy-mode;
clocks = <&tegra_car 22>, <&tegra_car 127>;
clock-names = "phy", "pll_u";
};
phy2: usb-phy@c5004400 {
compatible = "nvidia,tegra20-usb-phy";
reg = <0xc5004400 0x3c00>;
phy_type = "ulpi";
clocks = <&tegra_car 94>, <&tegra_car 127>;
clock-names = "phy", "pll_u";
};
phy3: usb-phy@c5008400 {
compatible = "nvidia,tegra20-usb-phy";
reg = <0xc5008400 0x3C00>;
phy_type = "utmi";
clocks = <&tegra_car 22>, <&tegra_car 127>;
clock-names = "phy", "pll_u";
};
usb@c5000000 {
compatible = "nvidia,tegra20-ehci", "usb-ehci";
reg = <0xc5000000 0x4000>;
......@@ -407,6 +432,8 @@ usb@c5000000 {
phy_type = "utmi";
nvidia,has-legacy-mode;
clocks = <&tegra_car 22>;
nvidia,needs-double-reset;
nvidia,phy = <&phy1>;
status = "disabled";
};
......@@ -416,6 +443,7 @@ usb@c5004000 {
interrupts = <0 21 0x04>;
phy_type = "ulpi";
clocks = <&tegra_car 58>;
nvidia,phy = <&phy2>;
status = "disabled";
};
......@@ -425,6 +453,7 @@ usb@c5008000 {
interrupts = <0 97 0x04>;
phy_type = "utmi";
clocks = <&tegra_car 59>;
nvidia,phy = <&phy3>;
status = "disabled";
};
......
......@@ -68,11 +68,11 @@ static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
};
static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0",
&tegra_ehci1_pdata),
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1",
&tegra_ehci2_pdata),
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2",
&tegra_ehci3_pdata),
{}
};
......
......@@ -240,15 +240,6 @@
#define TEGRA_CSITE_BASE 0x70040000
#define TEGRA_CSITE_SIZE SZ_256K
#define TEGRA_USB_BASE 0xC5000000
#define TEGRA_USB_SIZE SZ_16K
#define TEGRA_USB2_BASE 0xC5004000
#define TEGRA_USB2_SIZE SZ_16K
#define TEGRA_USB3_BASE 0xC5008000
#define TEGRA_USB3_SIZE SZ_16K
#define TEGRA_SDMMC1_BASE 0xC8000000
#define TEGRA_SDMMC1_SIZE SZ_512
......
......@@ -2,7 +2,7 @@
* EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs
*
* Copyright (C) 2010 Google, Inc.
* Copyright (C) 2009 NVIDIA Corporation
* Copyright (C) 2009 - 2013 NVIDIA Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
......@@ -26,23 +26,28 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/usb/ehci_def.h>
#include <linux/usb/tegra_usb_phy.h>
#define TEGRA_USB_BASE 0xC5000000
#define TEGRA_USB2_BASE 0xC5004000
#define TEGRA_USB3_BASE 0xC5008000
/* PORTSC registers */
#define TEGRA_USB_PORTSC1 0x184
#define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
#define TEGRA_USB_PORTSC1_PHCD (1 << 23)
#define TEGRA_USB_DMA_ALIGN 32
struct tegra_ehci_hcd {
struct ehci_hcd *ehci;
struct tegra_usb_phy *phy;
struct clk *clk;
struct clk *emc_clk;
struct usb_phy *transceiver;
int host_resumed;
int port_resuming;
bool needs_double_reset;
enum tegra_usb_phy_port_speed port_speed;
};
......@@ -50,9 +55,8 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd)
{
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
clk_prepare_enable(tegra->emc_clk);
clk_prepare_enable(tegra->clk);
usb_phy_set_suspend(&tegra->phy->u_phy, 0);
usb_phy_set_suspend(hcd->phy, 0);
tegra->host_resumed = 1;
}
......@@ -61,9 +65,8 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd)
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
tegra->host_resumed = 0;
usb_phy_set_suspend(&tegra->phy->u_phy, 1);
usb_phy_set_suspend(hcd->phy, 1);
clk_disable_unprepare(tegra->clk);
clk_disable_unprepare(tegra->emc_clk);
}
static int tegra_ehci_internal_port_reset(
......@@ -156,7 +159,7 @@ static int tegra_ehci_hub_control(
if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
/* Resume completed, re-enable disconnect detection */
tegra->port_resuming = 0;
tegra_usb_phy_postresume(tegra->phy);
tegra_usb_phy_postresume(hcd->phy);
}
}
......@@ -184,7 +187,7 @@ static int tegra_ehci_hub_control(
}
/* For USB1 port we need to issue Port Reset twice internally */
if (tegra->phy->instance == 0 &&
if (tegra->needs_double_reset &&
(typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) {
spin_unlock_irqrestore(&ehci->lock, flags);
return tegra_ehci_internal_port_reset(ehci, status_reg);
......@@ -209,7 +212,7 @@ static int tegra_ehci_hub_control(
goto done;
/* Disable disconnect detection during port resume */
tegra_usb_phy_preresume(tegra->phy);
tegra_usb_phy_preresume(hcd->phy);
ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
......@@ -473,7 +476,7 @@ static int controller_resume(struct device *dev)
}
/* Force the phy to keep data lines in suspend state */
tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed);
tegra_ehci_phy_restore_start(hcd->phy, tegra->port_speed);
/* Enable host mode */
tdi_reset(ehci);
......@@ -540,17 +543,17 @@ static int controller_resume(struct device *dev)
}
}
tegra_ehci_phy_restore_end(tegra->phy);
tegra_ehci_phy_restore_end(hcd->phy);
goto done;
restart:
if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH)
tegra_ehci_phy_restore_end(tegra->phy);
tegra_ehci_phy_restore_end(hcd->phy);
tegra_ehci_restart(hcd);
done:
tegra_usb_phy_preresume(tegra->phy);
tegra_usb_phy_preresume(hcd->phy);
tegra->port_resuming = 1;
return 0;
}
......@@ -604,6 +607,37 @@ static const struct dev_pm_ops tegra_ehci_pm_ops = {
#endif
/* Bits of PORTSC1, which will get cleared by writing 1 into them */
#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val)
{
unsigned long val;
struct usb_hcd *hcd = bus_to_hcd(x->otg->host);
void __iomem *base = hcd->regs;
val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
val &= ~TEGRA_USB_PORTSC1_PTS(3);
val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3);
writel(val, base + TEGRA_USB_PORTSC1);
}
EXPORT_SYMBOL_GPL(tegra_ehci_set_pts);
void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
{
unsigned long val;
struct usb_hcd *hcd = bus_to_hcd(x->otg->host);
void __iomem *base = hcd->regs;
val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
if (enable)
val |= TEGRA_USB_PORTSC1_PHCD;
else
val &= ~TEGRA_USB_PORTSC1_PHCD;
writel(val, base + TEGRA_USB_PORTSC1);
}
EXPORT_SYMBOL_GPL(tegra_ehci_set_phcd);
static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32);
static int tegra_ehci_probe(struct platform_device *pdev)
......@@ -615,6 +649,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
int err = 0;
int irq;
int instance = pdev->id;
struct usb_phy *u_phy;
pdata = pdev->dev.platform_data;
if (!pdata) {
......@@ -656,15 +691,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (err)
goto fail_clk;
tegra->emc_clk = devm_clk_get(&pdev->dev, "emc");
if (IS_ERR(tegra->emc_clk)) {
dev_err(&pdev->dev, "Can't get emc clock\n");
err = PTR_ERR(tegra->emc_clk);
goto fail_emc_clk;
}
clk_prepare_enable(tegra->emc_clk);
clk_set_rate(tegra->emc_clk, 400000000);
tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node,
"nvidia,needs-double-reset");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
......@@ -712,9 +740,19 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto fail_io;
}
usb_phy_init(&tegra->phy->u_phy);
hcd->phy = u_phy = &tegra->phy->u_phy;
usb_phy_init(hcd->phy);
u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
GFP_KERNEL);
if (!u_phy->otg) {
dev_err(&pdev->dev, "Failed to alloc memory for otg\n");
err = -ENOMEM;
goto fail_io;
}
u_phy->otg->host = hcd_to_bus(hcd);
err = usb_phy_set_suspend(&tegra->phy->u_phy, 0);
err = usb_phy_set_suspend(hcd->phy, 0);
if (err) {
dev_err(&pdev->dev, "Failed to power on the phy\n");
goto fail;
......@@ -760,10 +798,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!IS_ERR_OR_NULL(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL);
#endif
usb_phy_shutdown(&tegra->phy->u_phy);
usb_phy_shutdown(hcd->phy);
fail_io:
clk_disable_unprepare(tegra->emc_clk);
fail_emc_clk:
clk_disable_unprepare(tegra->clk);
fail_clk:
usb_put_hcd(hcd);
......@@ -784,15 +820,12 @@ static int tegra_ehci_remove(struct platform_device *pdev)
otg_set_host(tegra->transceiver->otg, NULL);
#endif
usb_phy_shutdown(hcd->phy);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
usb_phy_shutdown(&tegra->phy->u_phy);
clk_disable_unprepare(tegra->clk);
clk_disable_unprepare(tegra->emc_clk);
return 0;
}
......
......@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
......@@ -35,19 +36,6 @@
#define ULPI_VIEWPORT 0x170
#define USB_PORTSC1 0x184
#define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
#define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26)
#define USB_PORTSC1_PHCD (1 << 23)
#define USB_PORTSC1_WKOC (1 << 22)
#define USB_PORTSC1_WKDS (1 << 21)
#define USB_PORTSC1_WKCN (1 << 20)
#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16)
#define USB_PORTSC1_PP (1 << 12)
#define USB_PORTSC1_SUSP (1 << 7)
#define USB_PORTSC1_PE (1 << 2)
#define USB_PORTSC1_CCS (1 << 0)
#define USB_SUSP_CTRL 0x400
#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
......@@ -208,11 +196,6 @@ static struct tegra_utmip_config utmip_default[] = {
},
};
static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
{
return (phy->instance == 1);
}
static int utmip_pad_open(struct tegra_usb_phy *phy)
{
phy->pad_clk = clk_get_sys("utmip-pad", NULL);
......@@ -221,7 +204,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy)
return PTR_ERR(phy->pad_clk);
}
if (phy->instance == 0) {
if (phy->is_legacy_phy) {
phy->pad_regs = phy->regs;
} else {
phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
......@@ -236,7 +219,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy)
static void utmip_pad_close(struct tegra_usb_phy *phy)
{
if (phy->instance != 0)
if (!phy->is_legacy_phy)
iounmap(phy->pad_regs);
clk_put(phy->pad_clk);
}
......@@ -305,7 +288,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
unsigned long val;
void __iomem *base = phy->regs;
if (phy->instance == 0) {
if (phy->is_legacy_phy) {
val = readl(base + USB_SUSP_CTRL);
val |= USB_SUSP_SET;
writel(val, base + USB_SUSP_CTRL);
......@@ -315,13 +298,8 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_SUSP_SET;
writel(val, base + USB_SUSP_CTRL);
}
if (phy->instance == 2) {
val = readl(base + USB_PORTSC1);
val |= USB_PORTSC1_PHCD;
writel(val, base + USB_PORTSC1);
}
} else
tegra_ehci_set_phcd(&phy->u_phy, true);
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
......@@ -332,7 +310,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
unsigned long val;
void __iomem *base = phy->regs;
if (phy->instance == 0) {
if (phy->is_legacy_phy) {
val = readl(base + USB_SUSP_CTRL);
val |= USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
......@@ -342,13 +320,8 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
}
if (phy->instance == 2) {
val = readl(base + USB_PORTSC1);
val &= ~USB_PORTSC1_PHCD;
writel(val, base + USB_PORTSC1);
}
} else
tegra_ehci_set_phcd(&phy->u_phy, false);
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
USB_PHY_CLK_VALID))
......@@ -365,7 +338,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val |= UTMIP_RESET;
writel(val, base + USB_SUSP_CTRL);
if (phy->instance == 0) {
if (phy->is_legacy_phy) {
val = readl(base + USB1_LEGACY_CTRL);
val |= USB1_NO_LEGACY_MODE;
writel(val, base + USB1_LEGACY_CTRL);
......@@ -440,16 +413,14 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
writel(val, base + UTMIP_BIAS_CFG1);
if (phy->instance == 0) {
if (phy->is_legacy_phy) {
val = readl(base + UTMIP_SPARE_CFG0);
if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
val &= ~FUSE_SETUP_SEL;
else
val |= FUSE_SETUP_SEL;
writel(val, base + UTMIP_SPARE_CFG0);
}
if (phy->instance == 2) {
} else {
val = readl(base + USB_SUSP_CTRL);
val |= UTMIP_PHY_ENABLE;
writel(val, base + USB_SUSP_CTRL);
......@@ -459,7 +430,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val &= ~UTMIP_RESET;
writel(val, base + USB_SUSP_CTRL);
if (phy->instance == 0) {
if (phy->is_legacy_phy) {
val = readl(base + USB1_LEGACY_CTRL);
val &= ~USB1_VBUS_SENSE_CTL_MASK;
val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
......@@ -472,11 +443,8 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
utmi_phy_clk_enable(phy);
if (phy->instance == 2) {
val = readl(base + USB_PORTSC1);
val &= ~USB_PORTSC1_PTS(~0);
writel(val, base + USB_PORTSC1);
}
if (!phy->is_legacy_phy)
tegra_ehci_set_pts(&phy->u_phy, 0);
return 0;
}
......@@ -621,10 +589,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
return ret;
}
val = readl(base + USB_PORTSC1);
val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
writel(val, base + USB_PORTSC1);
val = readl(base + USB_SUSP_CTRL);
val |= USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
......@@ -639,17 +603,8 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
struct tegra_ulpi_config *config = phy->config;
/* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
* Controller to immediately bring the ULPI PHY out of low power
*/
val = readl(base + USB_PORTSC1);
val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
writel(val, base + USB_PORTSC1);
clk_disable(phy->clk);
return gpio_direction_output(config->reset_gpio, 0);
}
......@@ -660,7 +615,7 @@ static int tegra_phy_init(struct usb_phy *x)
struct tegra_ulpi_config *ulpi_config;
int err;
if (phy_is_ulpi(phy)) {
if (phy->is_ulpi_phy) {
ulpi_config = phy->config;
phy->clk = clk_get_sys(NULL, ulpi_config->clk);
if (IS_ERR(phy->clk)) {
......@@ -698,7 +653,7 @@ static void tegra_usb_phy_close(struct usb_phy *x)
{
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
if (phy_is_ulpi(phy))
if (phy->is_ulpi_phy)
clk_put(phy->clk);
else
utmip_pad_close(phy);
......@@ -709,7 +664,7 @@ static void tegra_usb_phy_close(struct usb_phy *x)
static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
{
if (phy_is_ulpi(phy))
if (phy->is_ulpi_phy)
return ulpi_phy_power_on(phy);
else
return utmi_phy_power_on(phy);
......@@ -717,7 +672,7 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
{
if (phy_is_ulpi(phy))
if (phy->is_ulpi_phy)
return ulpi_phy_power_off(phy);
else
return utmi_phy_power_off(phy);
......@@ -739,8 +694,9 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
unsigned long parent_rate;
int i;
int err;
struct device_node *np = dev->of_node;
phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
if (!phy)
return ERR_PTR(-ENOMEM);
......@@ -749,9 +705,16 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
phy->config = config;
phy->mode = phy_mode;
phy->dev = dev;
phy->is_legacy_phy =
of_property_read_bool(np, "nvidia,has-legacy-mode");
err = of_property_match_string(np, "phy_type", "ulpi");
if (err < 0)
phy->is_ulpi_phy = false;
else
phy->is_ulpi_phy = true;
if (!phy->config) {
if (phy_is_ulpi(phy)) {
if (phy->is_ulpi_phy) {
pr_err("%s: ulpi phy configuration missing", __func__);
err = -EINVAL;
goto err0;
......@@ -796,45 +759,40 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
void tegra_usb_phy_preresume(struct usb_phy *x)
{
if (!phy_is_ulpi(phy))
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
if (!phy->is_ulpi_phy)
utmi_phy_preresume(phy);
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
void tegra_usb_phy_postresume(struct usb_phy *x)
{
if (!phy_is_ulpi(phy))
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
if (!phy->is_ulpi_phy)
utmi_phy_postresume(phy);
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
void tegra_ehci_phy_restore_start(struct usb_phy *x,
enum tegra_usb_phy_port_speed port_speed)
{
if (!phy_is_ulpi(phy))
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
if (!phy->is_ulpi_phy)
utmi_phy_restore_start(phy, port_speed);
}
EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
void tegra_ehci_phy_restore_end(struct usb_phy *x)
{
if (!phy_is_ulpi(phy))
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
if (!phy->is_ulpi_phy)
utmi_phy_restore_end(phy);
}
EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_clk_disable(phy);
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable);
void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_clk_enable(phy);
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
......@@ -59,22 +59,24 @@ struct tegra_usb_phy {
struct usb_phy *ulpi;
struct usb_phy u_phy;
struct device *dev;
bool is_legacy_phy;
bool is_ulpi_phy;
};
struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode);
void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
void tegra_usb_phy_preresume(struct usb_phy *phy);
void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
void tegra_usb_phy_postresume(struct usb_phy *phy);
void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
void tegra_ehci_phy_restore_start(struct usb_phy *phy,
enum tegra_usb_phy_port_speed port_speed);
void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
void tegra_ehci_phy_restore_end(struct usb_phy *phy);
void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
enum tegra_usb_phy_port_speed port_speed);
void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val);
void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
void tegra_ehci_set_phcd(struct usb_phy *x, bool enable);
#endif /* __TEGRA_USB_PHY_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment