summaryrefslogtreecommitdiff
path: root/drivers/usb/chipidea
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r--drivers/usb/chipidea/bits.h12
-rw-r--r--drivers/usb/chipidea/ci.h9
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c19
-rw-r--r--drivers/usb/chipidea/ci_hdrc_usb2.c25
-rw-r--r--drivers/usb/chipidea/core.c141
-rw-r--r--drivers/usb/chipidea/debug.c7
-rw-r--r--drivers/usb/chipidea/host.c33
-rw-r--r--drivers/usb/chipidea/host.h6
-rw-r--r--drivers/usb/chipidea/otg_fsm.c1
-rw-r--r--drivers/usb/chipidea/udc.c114
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c12
11 files changed, 296 insertions, 83 deletions
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 3cb9bda51ddf..e462f55c8b99 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -25,6 +25,9 @@
#define VERSION (0xF << 25)
#define CIVERSION (0x7 << 29)
+/* SBUSCFG */
+#define AHBBRST_MASK 0x7
+
/* HCCPARAMS */
#define HCCPARAMS_LEN BIT(17)
@@ -53,6 +56,15 @@
#define DEVICEADDR_USBADRA BIT(24)
#define DEVICEADDR_USBADR (0x7FUL << 25)
+/* TTCTRL */
+#define TTCTRL_TTHA_MASK (0x7fUL << 24)
+/* Set non-zero value for internal TT Hub address representation */
+#define TTCTRL_TTHA (0x7fUL << 24)
+
+/* BURSTSIZE */
+#define RX_BURST_MASK 0xff
+#define TX_BURST_MASK 0xff00
+
/* PORTSC */
#define PORTSC_CCS BIT(0)
#define PORTSC_CSC BIT(1)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 6d6200e37b71..41d7cf6d63ba 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -50,6 +50,8 @@ enum ci_hw_regs {
OP_USBINTR,
OP_DEVICEADDR,
OP_ENDPTLISTADDR,
+ OP_TTCTRL,
+ OP_BURSTSIZE,
OP_PORTSC,
OP_DEVLC,
OP_OTGSC,
@@ -406,8 +408,11 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci)
{
#ifdef CONFIG_USB_OTG_FSM
+ struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
+
return ci->is_otg && ci->roles[CI_ROLE_HOST] &&
- ci->roles[CI_ROLE_GADGET];
+ ci->roles[CI_ROLE_GADGET] && (otg_caps->srp_support ||
+ otg_caps->hnp_support || otg_caps->adp_support);
#else
return false;
#endif
@@ -426,4 +431,6 @@ u8 hw_port_test_get(struct ci_hdrc *ci);
int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
u32 value, unsigned int timeout_ms);
+void ci_platform_configure(struct ci_hdrc *ci);
+
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 389f0e034259..dcc50c878159 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -29,26 +29,31 @@ struct ci_hdrc_imx_platform_flag {
};
static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
+ CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
.flags = CI_HDRC_IMX28_WRITE_FIX |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_HOST_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_HOST_STREAMING,
};
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
@@ -56,7 +61,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
- { .compatible = "fsl,imx6sx-usb", .data = &imx6sl_usb_data},
+ { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
@@ -104,7 +109,7 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
misc_pdev = of_find_device_by_node(args.np);
of_node_put(args.np);
- if (!misc_pdev)
+ if (!misc_pdev || !platform_get_drvdata(misc_pdev))
return ERR_PTR(-EPROBE_DEFER);
data->dev = &misc_pdev->dev;
@@ -126,7 +131,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
- .flags = CI_HDRC_DISABLE_STREAMING,
+ .flags = CI_HDRC_SET_NON_ZERO_TTHA,
};
int ret;
const struct of_device_id *of_id =
diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c
index 9eae1a16cef9..4456d2cf80ff 100644
--- a/drivers/usb/chipidea/ci_hdrc_usb2.c
+++ b/drivers/usb/chipidea/ci_hdrc_usb2.c
@@ -12,6 +12,7 @@
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/usb/chipidea.h>
@@ -30,18 +31,36 @@ static const struct ci_hdrc_platform_data ci_default_pdata = {
.flags = CI_HDRC_DISABLE_STREAMING,
};
+static struct ci_hdrc_platform_data ci_zynq_pdata = {
+ .capoffset = DEF_CAPOFFSET,
+};
+
+static const struct of_device_id ci_hdrc_usb2_of_match[] = {
+ { .compatible = "chipidea,usb2"},
+ { .compatible = "xlnx,zynq-usb-2.20a", .data = &ci_zynq_pdata},
+ { }
+};
+MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
+
static int ci_hdrc_usb2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ci_hdrc_usb2_priv *priv;
struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev);
int ret;
+ const struct of_device_id *match;
if (!ci_pdata) {
ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL);
*ci_pdata = ci_default_pdata; /* struct copy */
}
+ match = of_match_device(ci_hdrc_usb2_of_match, &pdev->dev);
+ if (match && match->data) {
+ /* struct copy */
+ *ci_pdata = *(struct ci_hdrc_platform_data *)match->data;
+ }
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -96,12 +115,6 @@ static int ci_hdrc_usb2_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id ci_hdrc_usb2_of_match[] = {
- { .compatible = "chipidea,usb2" },
- { }
-};
-MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
-
static struct platform_driver ci_hdrc_usb2_driver = {
.probe = ci_hdrc_usb2_probe,
.remove = ci_hdrc_usb2_remove,
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 74fea4fa41b1..3feebf7f31f0 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -64,6 +64,7 @@
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/regulator/consumer.h>
+#include <linux/usb/ehci_def.h>
#include "ci.h"
#include "udc.h"
@@ -84,6 +85,8 @@ static const u8 ci_regs_nolpm[] = {
[OP_USBINTR] = 0x08U,
[OP_DEVICEADDR] = 0x14U,
[OP_ENDPTLISTADDR] = 0x18U,
+ [OP_TTCTRL] = 0x1CU,
+ [OP_BURSTSIZE] = 0x20U,
[OP_PORTSC] = 0x44U,
[OP_DEVLC] = 0x84U,
[OP_OTGSC] = 0x64U,
@@ -106,6 +109,8 @@ static const u8 ci_regs_lpm[] = {
[OP_USBINTR] = 0x08U,
[OP_DEVICEADDR] = 0x14U,
[OP_ENDPTLISTADDR] = 0x18U,
+ [OP_TTCTRL] = 0x1CU,
+ [OP_BURSTSIZE] = 0x20U,
[OP_PORTSC] = 0x44U,
[OP_DEVLC] = 0x84U,
[OP_OTGSC] = 0xC4U,
@@ -118,7 +123,7 @@ static const u8 ci_regs_lpm[] = {
[OP_ENDPTCTRL] = 0xECU,
};
-static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
+static void hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
{
int i;
@@ -134,7 +139,6 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
? ci_regs_lpm[OP_ENDPTCTRL]
: ci_regs_nolpm[OP_ENDPTCTRL]);
- return 0;
}
static enum ci_revision ci_get_revision(struct ci_hdrc *ci)
@@ -403,6 +407,55 @@ static int ci_usb_phy_init(struct ci_hdrc *ci)
return ret;
}
+
+/**
+ * ci_platform_configure: do controller configure
+ * @ci: the controller
+ *
+ */
+void ci_platform_configure(struct ci_hdrc *ci)
+{
+ bool is_device_mode, is_host_mode;
+
+ is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC;
+ is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC;
+
+ if (is_device_mode &&
+ (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING))
+ hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
+ if (is_host_mode &&
+ (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING))
+ hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
+ if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {
+ if (ci->hw_bank.lpm)
+ hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);
+ else
+ hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
+ }
+
+ if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA)
+ hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA);
+
+ hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16);
+
+ if (ci->platdata->flags & CI_HDRC_OVERRIDE_AHB_BURST)
+ hw_write_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK,
+ ci->platdata->ahb_burst_config);
+
+ /* override burst size, take effect only when ahb_burst_config is 0 */
+ if (!hw_read_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK)) {
+ if (ci->platdata->flags & CI_HDRC_OVERRIDE_TX_BURST)
+ hw_write(ci, OP_BURSTSIZE, TX_BURST_MASK,
+ ci->platdata->tx_burst_size << __ffs(TX_BURST_MASK));
+
+ if (ci->platdata->flags & CI_HDRC_OVERRIDE_RX_BURST)
+ hw_write(ci, OP_BURSTSIZE, RX_BURST_MASK,
+ ci->platdata->rx_burst_size);
+ }
+}
+
/**
* hw_controller_reset: do controller reset
* @ci: the controller
@@ -447,16 +500,6 @@ int hw_device_reset(struct ci_hdrc *ci)
ci->platdata->notify_event(ci,
CI_HDRC_CONTROLLER_RESET_EVENT);
- if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
- hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
-
- if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {
- if (ci->hw_bank.lpm)
- hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);
- else
- hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
- }
-
/* USBMODE should be configured step by step */
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC);
@@ -469,6 +512,8 @@ int hw_device_reset(struct ci_hdrc *ci)
return -ENODEV;
}
+ ci_platform_configure(ci);
+
return 0;
}
@@ -560,6 +605,8 @@ static irqreturn_t ci_irq(int irq, void *data)
static int ci_get_platdata(struct device *dev,
struct ci_hdrc_platform_data *platdata)
{
+ int ret;
+
if (!platdata->phy_mode)
platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
@@ -588,9 +635,66 @@ static int ci_get_platdata(struct device *dev,
of_usb_host_tpl_support(dev->of_node);
}
+ if (platdata->dr_mode == USB_DR_MODE_OTG) {
+ /* We can support HNP and SRP of OTG 2.0 */
+ platdata->ci_otg_caps.otg_rev = 0x0200;
+ platdata->ci_otg_caps.hnp_support = true;
+ platdata->ci_otg_caps.srp_support = true;
+
+ /* Update otg capabilities by DT properties */
+ ret = of_usb_update_otg_caps(dev->of_node,
+ &platdata->ci_otg_caps);
+ if (ret)
+ return ret;
+ }
+
if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
+ platdata->itc_setting = 1;
+ if (of_find_property(dev->of_node, "itc-setting", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "itc-setting",
+ &platdata->itc_setting);
+ if (ret) {
+ dev_err(dev,
+ "failed to get itc-setting\n");
+ return ret;
+ }
+ }
+
+ if (of_find_property(dev->of_node, "ahb-burst-config", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "ahb-burst-config",
+ &platdata->ahb_burst_config);
+ if (ret) {
+ dev_err(dev,
+ "failed to get ahb-burst-config\n");
+ return ret;
+ }
+ platdata->flags |= CI_HDRC_OVERRIDE_AHB_BURST;
+ }
+
+ if (of_find_property(dev->of_node, "tx-burst-size-dword", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "tx-burst-size-dword",
+ &platdata->tx_burst_size);
+ if (ret) {
+ dev_err(dev,
+ "failed to get tx-burst-size-dword\n");
+ return ret;
+ }
+ platdata->flags |= CI_HDRC_OVERRIDE_TX_BURST;
+ }
+
+ if (of_find_property(dev->of_node, "rx-burst-size-dword", NULL)) {
+ ret = of_property_read_u32(dev->of_node, "rx-burst-size-dword",
+ &platdata->rx_burst_size);
+ if (ret) {
+ dev_err(dev,
+ "failed to get rx-burst-size-dword\n");
+ return ret;
+ }
+ platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
+ }
+
return 0;
}
@@ -1024,7 +1128,18 @@ static struct platform_driver ci_hdrc_driver = {
},
};
-module_platform_driver(ci_hdrc_driver);
+static int __init ci_hdrc_platform_register(void)
+{
+ ci_hdrc_host_driver_init();
+ return platform_driver_register(&ci_hdrc_driver);
+}
+module_init(ci_hdrc_platform_register);
+
+static void __exit ci_hdrc_platform_unregister(void)
+{
+ platform_driver_unregister(&ci_hdrc_driver);
+}
+module_exit(ci_hdrc_platform_unregister);
MODULE_ALIAS("platform:ci_hdrc");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 5b7061a33103..080b7be3daf0 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -10,6 +10,7 @@
#include <linux/usb/phy.h>
#include <linux/usb/otg.h>
#include <linux/usb/otg-fsm.h>
+#include <linux/usb/chipidea.h>
#include "ci.h"
#include "udc.h"
@@ -66,9 +67,11 @@ static int ci_port_test_show(struct seq_file *s, void *data)
unsigned long flags;
unsigned mode;
+ pm_runtime_get_sync(ci->dev);
spin_lock_irqsave(&ci->lock, flags);
mode = hw_port_test_get(ci);
spin_unlock_irqrestore(&ci->lock, flags);
+ pm_runtime_put_sync(ci->dev);
seq_printf(s, "mode = %u\n", mode);
@@ -98,9 +101,11 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
if (sscanf(buf, "%u", &mode) != 1)
return -EINVAL;
+ pm_runtime_get_sync(ci->dev);
spin_lock_irqsave(&ci->lock, flags);
ret = hw_port_test_set(ci, mode);
spin_unlock_irqrestore(&ci->lock, flags);
+ pm_runtime_put_sync(ci->dev);
return ret ? ret : count;
}
@@ -316,8 +321,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
if (role == CI_ROLE_END || role == ci->role)
return -EINVAL;
+ pm_runtime_get_sync(ci->dev);
ci_role_stop(ci);
ret = ci_role_start(ci, role);
+ pm_runtime_put_sync(ci->dev);
return ret ? ret : count;
}
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 6cf87b8b13a8..3d24304405b3 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -37,15 +37,14 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd);
struct ehci_ci_priv {
struct regulator *reg_vbus;
- struct ci_hdrc *ci;
};
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv;
- struct ci_hdrc *ci = priv->ci;
struct device *dev = hcd->self.controller;
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
int ret = 0;
int port = HCS_N_PORTS(ehci->hcs_params);
@@ -78,9 +77,25 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
return 0;
};
+static int ehci_ci_reset(struct usb_hcd *hcd)
+{
+ struct device *dev = hcd->self.controller;
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ehci_setup(hcd);
+ if (ret)
+ return ret;
+
+ ci_platform_configure(ci);
+
+ return ret;
+}
+
static const struct ehci_driver_overrides ehci_ci_overrides = {
.extra_priv_size = sizeof(struct ehci_ci_priv),
.port_power = ehci_ci_portpower,
+ .reset = ehci_ci_reset,
};
static irqreturn_t host_irq(struct ci_hdrc *ci)
@@ -123,7 +138,6 @@ static int host_start(struct ci_hdrc *ci)
priv = (struct ehci_ci_priv *)ehci->priv;
priv->reg_vbus = NULL;
- priv->ci = ci;
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
@@ -153,12 +167,6 @@ static int host_start(struct ci_hdrc *ci)
}
}
- if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
- hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
-
- if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED)
- hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
-
return ret;
disable_reg:
@@ -249,9 +257,12 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;
+ return 0;
+}
+
+void ci_hdrc_host_driver_init(void)
+{
ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
orig_bus_suspend = ci_ehci_hc_driver.bus_suspend;
ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend;
-
- return 0;
}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
index 5707bf379bfb..0f12f131bdd3 100644
--- a/drivers/usb/chipidea/host.h
+++ b/drivers/usb/chipidea/host.h
@@ -5,6 +5,7 @@
int ci_hdrc_host_init(struct ci_hdrc *ci);
void ci_hdrc_host_destroy(struct ci_hdrc *ci);
+void ci_hdrc_host_driver_init(void);
#else
@@ -18,6 +19,11 @@ static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
}
+static void ci_hdrc_host_driver_init(void)
+{
+
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 19d655a743b5..00ab59d45da1 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -525,7 +525,6 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
ci_role_start(ci, CI_ROLE_HOST);
} else {
ci_role_stop(ci);
- hw_device_reset(ci);
ci_role_start(ci, CI_ROLE_GADGET);
}
return 0;
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 764f668d45a9..8223fe73ea85 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -445,7 +445,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
rest -= count;
}
- if (hwreq->req.zero && hwreq->req.length
+ if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX
&& (hwreq->req.length % hwep->ep.maxpacket == 0))
add_td_to_list(hwep, hwreq, 0);
@@ -656,6 +656,44 @@ __acquires(hwep->lock)
return 0;
}
+static int _ep_set_halt(struct usb_ep *ep, int value, bool check_transfer)
+{
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL || hwep->ep.desc == NULL)
+ return -EINVAL;
+
+ if (usb_endpoint_xfer_isoc(hwep->ep.desc))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(hwep->lock, flags);
+
+ if (value && hwep->dir == TX && check_transfer &&
+ !list_empty(&hwep->qh.queue) &&
+ !usb_endpoint_xfer_control(hwep->ep.desc)) {
+ spin_unlock_irqrestore(hwep->lock, flags);
+ return -EAGAIN;
+ }
+
+ direction = hwep->dir;
+ do {
+ retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
+
+ if (!value)
+ hwep->wedge = 0;
+
+ if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
+ hwep->dir = (hwep->dir == TX) ? RX : TX;
+
+ } while (hwep->dir != direction);
+
+ spin_unlock_irqrestore(hwep->lock, flags);
+ return retval;
+}
+
+
/**
* _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
* @gadget: gadget
@@ -1051,7 +1089,7 @@ __acquires(ci->lock)
num += ci->hw_ep_max / 2;
spin_unlock(&ci->lock);
- err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep);
+ err = _ep_set_halt(&ci->ci_hw_ep[num].ep, 1, false);
spin_lock(&ci->lock);
if (!err)
isr_setup_status_phase(ci);
@@ -1090,6 +1128,13 @@ __acquires(ci->lock)
if (ci_otg_is_fsm_mode(ci))
err = otg_a_alt_hnp_support(ci);
break;
+ case USB_DEVICE_A_HNP_SUPPORT:
+ if (ci_otg_is_fsm_mode(ci)) {
+ ci->gadget.a_hnp_support = 1;
+ err = isr_setup_status_phase(
+ ci);
+ }
+ break;
default:
goto delegate;
}
@@ -1110,8 +1155,8 @@ delegate:
if (err < 0) {
spin_unlock(&ci->lock);
- if (usb_ep_set_halt(&hwep->ep))
- dev_err(ci->dev, "error: ep_set_halt\n");
+ if (_ep_set_halt(&hwep->ep, 1, false))
+ dev_err(ci->dev, "error: _ep_set_halt\n");
spin_lock(&ci->lock);
}
}
@@ -1142,9 +1187,9 @@ __acquires(ci->lock)
err = isr_setup_status_phase(ci);
if (err < 0) {
spin_unlock(&ci->lock);
- if (usb_ep_set_halt(&hwep->ep))
+ if (_ep_set_halt(&hwep->ep, 1, false))
dev_err(ci->dev,
- "error: ep_set_halt\n");
+ "error: _ep_set_halt\n");
spin_lock(&ci->lock);
}
}
@@ -1390,41 +1435,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
*/
static int ep_set_halt(struct usb_ep *ep, int value)
{
- struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
- int direction, retval = 0;
- unsigned long flags;
-
- if (ep == NULL || hwep->ep.desc == NULL)
- return -EINVAL;
-
- if (usb_endpoint_xfer_isoc(hwep->ep.desc))
- return -EOPNOTSUPP;
-
- spin_lock_irqsave(hwep->lock, flags);
-
-#ifndef STALL_IN
- /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
- if (value && hwep->type == USB_ENDPOINT_XFER_BULK && hwep->dir == TX &&
- !list_empty(&hwep->qh.queue)) {
- spin_unlock_irqrestore(hwep->lock, flags);
- return -EAGAIN;
- }
-#endif
-
- direction = hwep->dir;
- do {
- retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
-
- if (!value)
- hwep->wedge = 0;
-
- if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
- hwep->dir = (hwep->dir == TX) ? RX : TX;
-
- } while (hwep->dir != direction);
-
- spin_unlock_irqrestore(hwep->lock, flags);
- return retval;
+ return _ep_set_halt(ep, value, true);
}
/**
@@ -1624,6 +1635,20 @@ static int init_eps(struct ci_hdrc *ci)
hwep->ep.name = hwep->name;
hwep->ep.ops = &usb_ep_ops;
+
+ if (i == 0) {
+ hwep->ep.caps.type_control = true;
+ } else {
+ hwep->ep.caps.type_iso = true;
+ hwep->ep.caps.type_bulk = true;
+ hwep->ep.caps.type_int = true;
+ }
+
+ if (j == TX)
+ hwep->ep.caps.dir_in = true;
+ else
+ hwep->ep.caps.dir_out = true;
+
/*
* for ep0: maxP defined in desc, for other
* eps, maxP is set by epautoconfig() called
@@ -1827,6 +1852,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
static int udc_start(struct ci_hdrc *ci)
{
struct device *dev = ci->dev;
+ struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
int retval = 0;
spin_lock_init(&ci->lock);
@@ -1834,8 +1860,12 @@ static int udc_start(struct ci_hdrc *ci)
ci->gadget.ops = &usb_gadget_ops;
ci->gadget.speed = USB_SPEED_UNKNOWN;
ci->gadget.max_speed = USB_SPEED_HIGH;
- ci->gadget.is_otg = ci->is_otg ? 1 : 0;
ci->gadget.name = ci->platdata->name;
+ ci->gadget.otg_caps = otg_caps;
+
+ if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support ||
+ otg_caps->adp_support))
+ ci->gadget.is_otg = 1;
INIT_LIST_HEAD(&ci->gadget.ep_list);
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 3cefd49ddb00..5ddab30ee240 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -54,6 +54,7 @@
#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
#define MX53_USB_PLL_DIV_24_MHZ 0x01
+#define MX6_BM_NON_BURST_SETTING BIT(1)
#define MX6_BM_OVER_CUR_DIS BIT(7)
#define MX6_BM_WAKEUP_ENABLE BIT(10)
#define MX6_BM_ID_WAKEUP BIT(16)
@@ -255,14 +256,21 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
if (data->index > 3)
return -EINVAL;
+ spin_lock_irqsave(&usbmisc->lock, flags);
+
if (data->disable_oc) {
- spin_lock_irqsave(&usbmisc->lock, flags);
reg = readl(usbmisc->base + data->index * 4);
writel(reg | MX6_BM_OVER_CUR_DIS,
usbmisc->base + data->index * 4);
- spin_unlock_irqrestore(&usbmisc->lock, flags);
}
+ /* SoC non-burst setting */
+ reg = readl(usbmisc->base + data->index * 4);
+ writel(reg | MX6_BM_NON_BURST_SETTING,
+ usbmisc->base + data->index * 4);
+
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
usbmisc_imx6q_set_wakeup(data, false);
return 0;