|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright 2012 Freescale Semiconductor, Inc.
|
|
|
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
|
|
|
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
|
|
|
* on behalf of DENX Software Engineering GmbH
|
|
|
*
|
|
@@ -20,6 +20,7 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/io.h>
|
|
|
+#include <linux/of_device.h>
|
|
|
|
|
|
#define DRIVER_NAME "mxs_phy"
|
|
|
|
|
@@ -34,13 +35,55 @@
|
|
|
#define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14)
|
|
|
#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1)
|
|
|
|
|
|
+#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
|
|
|
+
|
|
|
+/* Do disconnection between PHY and controller without vbus */
|
|
|
+#define MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS BIT(0)
|
|
|
+
|
|
|
+/*
|
|
|
+ * The PHY will be in messy if there is a wakeup after putting
|
|
|
+ * bus to suspend (set portsc.suspendM) but before setting PHY to low
|
|
|
+ * power mode (set portsc.phcd).
|
|
|
+ */
|
|
|
+#define MXS_PHY_ABNORMAL_IN_SUSPEND BIT(1)
|
|
|
+
|
|
|
+/*
|
|
|
+ * The SOF sends too fast after resuming, it will cause disconnection
|
|
|
+ * between host and high speed device.
|
|
|
+ */
|
|
|
+#define MXS_PHY_SENDING_SOF_TOO_FAST BIT(2)
|
|
|
+
|
|
|
+struct mxs_phy_data {
|
|
|
+ unsigned int flags;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct mxs_phy_data imx23_phy_data = {
|
|
|
+ .flags = MXS_PHY_ABNORMAL_IN_SUSPEND | MXS_PHY_SENDING_SOF_TOO_FAST,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct mxs_phy_data imx6q_phy_data = {
|
|
|
+ .flags = MXS_PHY_SENDING_SOF_TOO_FAST |
|
|
|
+ MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct mxs_phy_data imx6sl_phy_data = {
|
|
|
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct of_device_id mxs_phy_dt_ids[] = {
|
|
|
+ { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
|
|
|
+ { .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
|
|
|
+ { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
|
|
|
+ { /* sentinel */ }
|
|
|
+};
|
|
|
+MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
|
|
|
+
|
|
|
struct mxs_phy {
|
|
|
struct usb_phy phy;
|
|
|
struct clk *clk;
|
|
|
+ const struct mxs_phy_data *data;
|
|
|
};
|
|
|
|
|
|
-#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
|
|
|
-
|
|
|
static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
|
|
|
{
|
|
|
int ret;
|
|
@@ -138,6 +181,8 @@ static int mxs_phy_probe(struct platform_device *pdev)
|
|
|
struct clk *clk;
|
|
|
struct mxs_phy *mxs_phy;
|
|
|
int ret;
|
|
|
+ const struct of_device_id *of_id =
|
|
|
+ of_match_device(mxs_phy_dt_ids, &pdev->dev);
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
base = devm_ioremap_resource(&pdev->dev, res);
|
|
@@ -168,6 +213,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
|
|
|
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
|
|
|
|
|
|
mxs_phy->clk = clk;
|
|
|
+ mxs_phy->data = of_id->data;
|
|
|
|
|
|
platform_set_drvdata(pdev, mxs_phy);
|
|
|
|
|
@@ -187,12 +233,6 @@ static int mxs_phy_remove(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static const struct of_device_id mxs_phy_dt_ids[] = {
|
|
|
- { .compatible = "fsl,imx23-usbphy", },
|
|
|
- { /* sentinel */ }
|
|
|
-};
|
|
|
-MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
|
|
|
-
|
|
|
static struct platform_driver mxs_phy_driver = {
|
|
|
.probe = mxs_phy_probe,
|
|
|
.remove = mxs_phy_remove,
|