summaryrefslogtreecommitdiff
path: root/drivers/usb/chipidea
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r--drivers/usb/chipidea/Kconfig6
-rw-r--r--drivers/usb/chipidea/Makefile6
-rw-r--r--drivers/usb/chipidea/bits.h16
-rw-r--r--drivers/usb/chipidea/ci.h51
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c (renamed from drivers/usb/chipidea/ci13xxx_imx.c)117
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.h (renamed from drivers/usb/chipidea/ci13xxx_imx.h)0
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c (renamed from drivers/usb/chipidea/ci13xxx_msm.c)49
-rw-r--r--drivers/usb/chipidea/ci_hdrc_pci.c (renamed from drivers/usb/chipidea/ci13xxx_pci.c)61
-rw-r--r--drivers/usb/chipidea/core.c109
-rw-r--r--drivers/usb/chipidea/debug.c61
-rw-r--r--drivers/usb/chipidea/debug.h8
-rw-r--r--drivers/usb/chipidea/host.c10
-rw-r--r--drivers/usb/chipidea/host.h4
-rw-r--r--drivers/usb/chipidea/udc.c785
-rw-r--r--drivers/usb/chipidea/udc.h26
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c15
16 files changed, 737 insertions, 587 deletions
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
index b2df442..eb2aa2e 100644
--- a/drivers/usb/chipidea/Kconfig
+++ b/drivers/usb/chipidea/Kconfig
@@ -12,15 +12,15 @@ if USB_CHIPIDEA
config USB_CHIPIDEA_UDC
bool "ChipIdea device controller"
- depends on USB_GADGET=y || USB_GADGET=USB_CHIPIDEA
+ depends on USB_GADGET=y || USB_CHIPIDEA=m
help
Say Y here to enable device controller functionality of the
ChipIdea driver.
config USB_CHIPIDEA_HOST
bool "ChipIdea host controller"
- depends on USB=y || USB=USB_CHIPIDEA
- depends on USB_EHCI_HCD=y
+ depends on USB=y
+ depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m
select USB_EHCI_ROOT_HUB_TT
help
Say Y here to enable host controller functionality of the
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 4ab83e9..3bbbcba 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -9,13 +9,13 @@ ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
# Glue/Bridge layers go here
-obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o
+obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o
# PCI doesn't provide stubs, need to check
ifneq ($(CONFIG_PCI),)
- obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o
+ obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_pci.o
endif
ifneq ($(CONFIG_OF_DEVICE),)
- obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o
+ obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_imx.o usbmisc_imx.o
endif
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 050de85..aefa026 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -48,10 +48,24 @@
#define PORTSC_SUSP BIT(7)
#define PORTSC_HSP BIT(9)
#define PORTSC_PTC (0x0FUL << 16)
+/* PTS and PTW for non lpm version only */
+#define PORTSC_PTS(d) \
+ ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
+#define PORTSC_PTW BIT(28)
+#define PORTSC_STS BIT(29)
/* DEVLC */
#define DEVLC_PSPD (0x03UL << 25)
-#define DEVLC_PSPD_HS (0x02UL << 25)
+#define DEVLC_PSPD_HS (0x02UL << 25)
+#define DEVLC_PTW BIT(27)
+#define DEVLC_STS BIT(28)
+#define DEVLC_PTS(d) (((d) & 0x7) << 29)
+
+/* Encoding for DEVLC_PTS and PORTSC_PTS */
+#define PTS_UTMI 0
+#define PTS_ULPI 2
+#define PTS_SERIAL 3
+#define PTS_HSIC 4
/* OTGSC */
#define OTGSC_IDPU BIT(5)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index b0a6bce..33cb29f 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -22,14 +22,14 @@
* DEFINE
*****************************************************************************/
#define TD_PAGE_COUNT 5
-#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
+#define CI_HDRC_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32
/******************************************************************************
* STRUCTURES
*****************************************************************************/
/**
- * struct ci13xxx_ep - endpoint representation
+ * struct ci_hw_ep - endpoint representation
* @ep: endpoint structure for gadget drivers
* @dir: endpoint direction (TX/RX)
* @num: endpoint number
@@ -41,7 +41,7 @@
* @lock: pointer to controller's spinlock
* @td_pool: pointer to controller's TD pool
*/
-struct ci13xxx_ep {
+struct ci_hw_ep {
struct usb_ep ep;
u8 dir;
u8 num;
@@ -49,15 +49,16 @@ struct ci13xxx_ep {
char name[16];
struct {
struct list_head queue;
- struct ci13xxx_qh *ptr;
+ struct ci_hw_qh *ptr;
dma_addr_t dma;
} qh;
int wedge;
/* global resources */
- struct ci13xxx *ci;
+ struct ci_hdrc *ci;
spinlock_t *lock;
struct dma_pool *td_pool;
+ struct td_node *pending_td;
};
enum ci_role {
@@ -74,9 +75,9 @@ enum ci_role {
* name: role name string (host/gadget)
*/
struct ci_role_driver {
- int (*start)(struct ci13xxx *);
- void (*stop)(struct ci13xxx *);
- irqreturn_t (*irq)(struct ci13xxx *);
+ int (*start)(struct ci_hdrc *);
+ void (*stop)(struct ci_hdrc *);
+ irqreturn_t (*irq)(struct ci_hdrc *);
const char *name;
};
@@ -101,7 +102,7 @@ struct hw_bank {
};
/**
- * struct ci13xxx - chipidea device representation
+ * struct ci_hdrc - chipidea device representation
* @dev: pointer to parent device
* @lock: access synchronization
* @hw_bank: hardware register mapping
@@ -116,7 +117,7 @@ struct hw_bank {
* @gadget: device side representation for peripheral controller
* @driver: gadget driver
* @hw_ep_max: total number of endpoints supported by hardware
- * @ci13xxx_ep: array of endpoints
+ * @ci_hw_ep: array of endpoints
* @ep0_dir: ep0 direction
* @ep0out: pointer to ep0 OUT endpoint
* @ep0in: pointer to ep0 IN endpoint
@@ -132,7 +133,7 @@ struct hw_bank {
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
*/
-struct ci13xxx {
+struct ci_hdrc {
struct device *dev;
spinlock_t lock;
struct hw_bank hw_bank;
@@ -149,9 +150,9 @@ struct ci13xxx {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
unsigned hw_ep_max;
- struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX];
+ struct ci_hw_ep ci_hw_ep[ENDPT_MAX];
u32 ep0_dir;
- struct ci13xxx_ep *ep0out, *ep0in;
+ struct ci_hw_ep *ep0out, *ep0in;
struct usb_request *status;
bool setaddr;
@@ -160,7 +161,7 @@ struct ci13xxx {
u8 suspended;
u8 test_mode;
- struct ci13xxx_platform_data *platdata;
+ struct ci_hdrc_platform_data *platdata;
int vbus_active;
/* FIXME: some day, we'll not use global phy */
bool global_phy;
@@ -169,13 +170,13 @@ struct ci13xxx {
struct dentry *debugfs;
};
-static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
+static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
{
BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
return ci->roles[ci->role];
}
-static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
+static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role)
{
int ret;
@@ -191,7 +192,7 @@ static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
return ret;
}
-static inline void ci_role_stop(struct ci13xxx *ci)
+static inline void ci_role_stop(struct ci_hdrc *ci)
{
enum ci_role role = ci->role;
@@ -210,7 +211,7 @@ static inline void ci_role_stop(struct ci13xxx *ci)
#define REG_BITS (32)
/* register indices */
-enum ci13xxx_regs {
+enum ci_hw_regs {
CAP_CAPLENGTH,
CAP_HCCPARAMS,
CAP_DCCPARAMS,
@@ -242,7 +243,7 @@ enum ci13xxx_regs {
*
* This function returns register contents
*/
-static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
+static inline u32 hw_read(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask)
{
return ioread32(ci->hw_bank.regmap[reg]) & mask;
}
@@ -253,7 +254,7 @@ static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
* @mask: bitfield mask
* @data: new value
*/
-static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
+static inline void hw_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
u32 mask, u32 data)
{
if (~mask)
@@ -270,7 +271,7 @@ static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
*
* This function returns register contents
*/
-static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
+static inline u32 hw_test_and_clear(struct ci_hdrc *ci, enum ci_hw_regs reg,
u32 mask)
{
u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask;
@@ -287,7 +288,7 @@ static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
*
* This function returns register contents
*/
-static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
+static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
u32 mask, u32 data)
{
u32 val = hw_read(ci, reg, ~0);
@@ -296,10 +297,10 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
return (val & mask) >> __ffs(mask);
}
-int hw_device_reset(struct ci13xxx *ci, u32 mode);
+int hw_device_reset(struct ci_hdrc *ci, u32 mode);
-int hw_port_test_set(struct ci13xxx *ci, u8 mode);
+int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
-u8 hw_port_test_get(struct ci13xxx *ci);
+u8 hw_port_test_get(struct ci_hdrc *ci);
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 73f9d5f..14362c0 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -20,16 +20,14 @@
#include <linux/usb/chipidea.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
-#include <linux/pinctrl/consumer.h>
#include "ci.h"
-#include "ci13xxx_imx.h"
+#include "ci_hdrc_imx.h"
#define pdev_to_phy(pdev) \
((struct usb_phy *)platform_get_drvdata(pdev))
-struct ci13xxx_imx_data {
- struct device_node *phy_np;
+struct ci_hdrc_imx_data {
struct usb_phy *phy;
struct platform_device *ci_pdev;
struct clk *clk;
@@ -88,22 +86,17 @@ EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
/* End of common functions shared by usbmisc drivers*/
-static struct ci13xxx_platform_data ci13xxx_imx_platdata = {
- .name = "ci13xxx_imx",
- .flags = CI13XXX_REQUIRE_TRANSCEIVER |
- CI13XXX_PULLUP_ON_VBUS |
- CI13XXX_DISABLE_STREAMING,
- .capoffset = DEF_CAPOFFSET,
-};
-
-static int ci13xxx_imx_probe(struct platform_device *pdev)
+static int ci_hdrc_imx_probe(struct platform_device *pdev)
{
- struct ci13xxx_imx_data *data;
- struct platform_device *plat_ci, *phy_pdev;
- struct device_node *phy_np;
+ struct ci_hdrc_imx_data *data;
+ struct ci_hdrc_platform_data pdata = {
+ .name = "ci_hdrc_imx",
+ .capoffset = DEF_CAPOFFSET,
+ .flags = CI_HDRC_REQUIRE_TRANSCEIVER |
+ CI_HDRC_PULLUP_ON_VBUS |
+ CI_HDRC_DISABLE_STREAMING,
+ };
struct resource *res;
- struct regulator *reg_vbus;
- struct pinctrl *pinctrl;
int ret;
if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL)
@@ -112,7 +105,7 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
- dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n");
+ dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n");
return -ENOMEM;
}
@@ -122,11 +115,6 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
return -ENOENT;
}
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- dev_warn(&pdev->dev, "pinctrl get/select failed, err=%ld\n",
- PTR_ERR(pinctrl));
-
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk)) {
dev_err(&pdev->dev,
@@ -141,37 +129,33 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
return ret;
}
- phy_np = of_parse_phandle(pdev->dev.of_node, "fsl,usbphy", 0);
- if (phy_np) {
- data->phy_np = phy_np;
- phy_pdev = of_find_device_by_node(phy_np);
- if (phy_pdev) {
- struct usb_phy *phy;
- phy = pdev_to_phy(phy_pdev);
- if (phy &&
- try_module_get(phy_pdev->dev.driver->owner)) {
- usb_phy_init(phy);
- data->phy = phy;
- }
+ data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
+ if (!IS_ERR(data->phy)) {
+ ret = usb_phy_init(data->phy);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to init phy: %d\n", ret);
+ goto err_clk;
}
+ } else if (PTR_ERR(data->phy) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_clk;
}
/* we only support host now, so enable vbus here */
- reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
- if (!IS_ERR(reg_vbus)) {
- ret = regulator_enable(reg_vbus);
+ data->reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
+ if (!IS_ERR(data->reg_vbus)) {
+ ret = regulator_enable(data->reg_vbus);
if (ret) {
dev_err(&pdev->dev,
"Failed to enable vbus regulator, err=%d\n",
ret);
- goto put_np;
+ goto err_clk;
}
- data->reg_vbus = reg_vbus;
} else {
- reg_vbus = NULL;
+ data->reg_vbus = NULL;
}
- ci13xxx_imx_platdata.phy = data->phy;
+ pdata.phy = data->phy;
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
@@ -187,11 +171,11 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
}
}
- plat_ci = ci13xxx_add_device(&pdev->dev,
+ data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
- &ci13xxx_imx_platdata);
- if (IS_ERR(plat_ci)) {
- ret = PTR_ERR(plat_ci);
+ &pdata);
+ if (IS_ERR(data->ci_pdev)) {
+ ret = PTR_ERR(data->ci_pdev);
dev_err(&pdev->dev,
"Can't register ci_hdrc platform device, err=%d\n",
ret);
@@ -203,11 +187,10 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"usbmisc post failed, ret=%d\n", ret);
- goto put_np;
+ goto disable_device;
}
}
- data->ci_pdev = plat_ci;
platform_set_drvdata(pdev, data);
pm_runtime_no_callbacks(&pdev->dev);
@@ -215,22 +198,22 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
return 0;
+disable_device:
+ ci_hdrc_remove_device(data->ci_pdev);
err:
- if (reg_vbus)
- regulator_disable(reg_vbus);
-put_np:
- if (phy_np)
- of_node_put(phy_np);
+ if (data->reg_vbus)
+ regulator_disable(data->reg_vbus);
+err_clk:
clk_disable_unprepare(data->clk);
return ret;
}
-static int ci13xxx_imx_remove(struct platform_device *pdev)
+static int ci_hdrc_imx_remove(struct platform_device *pdev)
{
- struct ci13xxx_imx_data *data = platform_get_drvdata(pdev);
+ struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
- ci13xxx_remove_device(data->ci_pdev);
+ ci_hdrc_remove_device(data->ci_pdev);
if (data->reg_vbus)
regulator_disable(data->reg_vbus);
@@ -240,35 +223,31 @@ static int ci13xxx_imx_remove(struct platform_device *pdev)
module_put(data->phy->dev->driver->owner);
}
- of_node_put(data->phy_np);
-
clk_disable_unprepare(data->clk);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
-static const struct of_device_id ci13xxx_imx_dt_ids[] = {
+static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx27-usb", },
{ /* sentinel */ }
};
-MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids);
+MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
-static struct platform_driver ci13xxx_imx_driver = {
- .probe = ci13xxx_imx_probe,
- .remove = ci13xxx_imx_remove,
+static struct platform_driver ci_hdrc_imx_driver = {
+ .probe = ci_hdrc_imx_probe,
+ .remove = ci_hdrc_imx_remove,
.driver = {
.name = "imx_usb",
.owner = THIS_MODULE,
- .of_match_table = ci13xxx_imx_dt_ids,
+ .of_match_table = ci_hdrc_imx_dt_ids,
},
};
-module_platform_driver(ci13xxx_imx_driver);
+module_platform_driver(ci_hdrc_imx_driver);
MODULE_ALIAS("platform:imx-usb");
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CI13xxx i.MX USB binding");
+MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h
index 550bfa4..550bfa4 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.h
+++ b/drivers/usb/chipidea/ci_hdrc_imx.h
diff --git a/drivers/usb/chipidea/ci13xxx_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index 7d16681..fb657ef 100644
--- a/drivers/usb/chipidea/ci13xxx_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -17,19 +17,19 @@
#define MSM_USB_BASE (ci->hw_bank.abs)
-static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
+static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
{
struct device *dev = ci->gadget.dev.parent;
int val;
switch (event) {
- case CI13XXX_CONTROLLER_RESET_EVENT:
- dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+ case CI_HDRC_CONTROLLER_RESET_EVENT:
+ dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel(0, USB_AHBMODE);
break;
- case CI13XXX_CONTROLLER_STOPPED_EVENT:
- dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n");
+ case CI_HDRC_CONTROLLER_STOPPED_EVENT:
+ dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
/*
* Put the transceiver in non-driving mode. Otherwise host
* may not detect soft-disconnection.
@@ -40,32 +40,32 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
usb_phy_io_write(ci->transceiver, val, ULPI_FUNC_CTRL);
break;
default:
- dev_dbg(dev, "unknown ci13xxx event\n");
+ dev_dbg(dev, "unknown ci_hdrc event\n");
break;
}
}
-static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
- .name = "ci13xxx_msm",
- .flags = CI13XXX_REGS_SHARED |
- CI13XXX_REQUIRE_TRANSCEIVER |
- CI13XXX_PULLUP_ON_VBUS |
- CI13XXX_DISABLE_STREAMING,
+static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
+ .name = "ci_hdrc_msm",
+ .flags = CI_HDRC_REGS_SHARED |
+ CI_HDRC_REQUIRE_TRANSCEIVER |
+ CI_HDRC_PULLUP_ON_VBUS |
+ CI_HDRC_DISABLE_STREAMING,
- .notify_event = ci13xxx_msm_notify_event,
+ .notify_event = ci_hdrc_msm_notify_event,
};
-static int ci13xxx_msm_probe(struct platform_device *pdev)
+static int ci_hdrc_msm_probe(struct platform_device *pdev)
{
struct platform_device *plat_ci;
- dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
+ dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n");
- plat_ci = ci13xxx_add_device(&pdev->dev,
+ plat_ci = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
- &ci13xxx_msm_platdata);
+ &ci_hdrc_msm_platdata);
if (IS_ERR(plat_ci)) {
- dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
+ dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
return PTR_ERR(plat_ci);
}
@@ -77,23 +77,24 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)
return 0;
}
-static int ci13xxx_msm_remove(struct platform_device *pdev)
+static int ci_hdrc_msm_remove(struct platform_device *pdev)
{
struct platform_device *plat_ci = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
- ci13xxx_remove_device(plat_ci);
+ ci_hdrc_remove_device(plat_ci);
return 0;
}
-static struct platform_driver ci13xxx_msm_driver = {
- .probe = ci13xxx_msm_probe,
- .remove = ci13xxx_msm_remove,
+static struct platform_driver ci_hdrc_msm_driver = {
+ .probe = ci_hdrc_msm_probe,
+ .remove = ci_hdrc_msm_remove,
.driver = { .name = "msm_hsusb", },
};
-module_platform_driver(ci13xxx_msm_driver);
+module_platform_driver(ci_hdrc_msm_driver);
MODULE_ALIAS("platform:msm_hsusb");
+MODULE_ALIAS("platform:ci13xxx_msm");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/chipidea/ci13xxx_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c
index 4e1fc61..042320a 100644
--- a/drivers/usb/chipidea/ci13xxx_pci.c
+++ b/drivers/usb/chipidea/ci_hdrc_pci.c
@@ -1,5 +1,5 @@
/*
- * ci13xxx_pci.c - MIPS USB IP core family device controller
+ * ci_hdrc_pci.c - MIPS USB IP core family device controller
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
*
@@ -18,29 +18,29 @@
#include <linux/usb/chipidea.h>
/* driver name */
-#define UDC_DRIVER_NAME "ci13xxx_pci"
+#define UDC_DRIVER_NAME "ci_hdrc_pci"
/******************************************************************************
* PCI block
*****************************************************************************/
-static struct ci13xxx_platform_data pci_platdata = {
+static struct ci_hdrc_platform_data pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = DEF_CAPOFFSET,
};
-static struct ci13xxx_platform_data langwell_pci_platdata = {
+static struct ci_hdrc_platform_data langwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
};
-static struct ci13xxx_platform_data penwell_pci_platdata = {
+static struct ci_hdrc_platform_data penwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
.power_budget = 200,
};
/**
- * ci13xxx_pci_probe: PCI probe
+ * ci_hdrc_pci_probe: PCI probe
* @pdev: USB device controller being probed
* @id: PCI hotplug ID connecting controller to UDC framework
*
@@ -48,10 +48,10 @@ static struct ci13xxx_platform_data penwell_pci_platdata = {
* Allocates basic PCI resources for this USB device controller, and then
* invokes the udc_probe() method to start the UDC associated with it
*/
-static int ci13xxx_pci_probe(struct pci_dev *pdev,
+static int ci_hdrc_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- struct ci13xxx_platform_data *platdata = (void *)id->driver_data;
+ struct ci_hdrc_platform_data *platdata = (void *)id->driver_data;
struct platform_device *plat_ci;
struct resource res[3];
int retval = 0, nres = 2;
@@ -61,17 +61,15 @@ static int ci13xxx_pci_probe(struct pci_dev *pdev,
return -ENODEV;
}
- retval = pci_enable_device(pdev);
+ retval = pcim_enable_device(pdev);
if (retval)
- goto done;
+ return retval;
if (!pdev->irq) {
dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
- retval = -ENODEV;
- goto disable_device;
+ return -ENODEV;
}
- pci_set_power_state(pdev, PCI_D0);
pci_set_master(pdev);
pci_try_set_mwi(pdev);
@@ -82,38 +80,30 @@ static int ci13xxx_pci_probe(struct pci_dev *pdev,
res[1].start = pdev->irq;
res[1].flags = IORESOURCE_IRQ;
- plat_ci = ci13xxx_add_device(&pdev->dev, res, nres, platdata);
+ plat_ci = ci_hdrc_add_device(&pdev->dev, res, nres, platdata);
if (IS_ERR(plat_ci)) {
- dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
- retval = PTR_ERR(plat_ci);
- goto disable_device;
+ dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
+ return PTR_ERR(plat_ci);
}
pci_set_drvdata(pdev, plat_ci);
return 0;
-
- disable_device:
- pci_disable_device(pdev);
- done:
- return retval;
}
/**
- * ci13xxx_pci_remove: PCI remove
+ * ci_hdrc_pci_remove: PCI remove
* @pdev: USB Device Controller being removed
*
- * Reverses the effect of ci13xxx_pci_probe(),
+ * Reverses the effect of ci_hdrc_pci_probe(),
* first invoking the udc_remove() and then releases
* all PCI resources allocated for this USB device controller
*/
-static void ci13xxx_pci_remove(struct pci_dev *pdev)
+static void ci_hdrc_pci_remove(struct pci_dev *pdev)
{
struct platform_device *plat_ci = pci_get_drvdata(pdev);
- ci13xxx_remove_device(plat_ci);
- pci_set_drvdata(pdev, NULL);
- pci_disable_device(pdev);
+ ci_hdrc_remove_device(plat_ci);
}
/**
@@ -122,7 +112,7 @@ static void ci13xxx_pci_remove(struct pci_dev *pdev)
*
* Check "pci.h" for details
*/
-static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
+static DEFINE_PCI_DEVICE_TABLE(ci_hdrc_pci_id_table) = {
{
PCI_DEVICE(0x153F, 0x1004),
.driver_data = (kernel_ulong_t)&pci_platdata,
@@ -141,18 +131,19 @@ static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
},
{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
};
-MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
+MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
-static struct pci_driver ci13xxx_pci_driver = {
+static struct pci_driver ci_hdrc_pci_driver = {
.name = UDC_DRIVER_NAME,
- .id_table = ci13xxx_pci_id_table,
- .probe = ci13xxx_pci_probe,
- .remove = ci13xxx_pci_remove,
+ .id_table = ci_hdrc_pci_id_table,
+ .probe = ci_hdrc_pci_probe,
+ .remove = ci_hdrc_pci_remove,
};
-module_pci_driver(ci13xxx_pci_driver);
+module_pci_driver(ci_hdrc_pci_driver);
MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
MODULE_LICENSE("GPL");
MODULE_VERSION("June 2008");
+MODULE_ALIAS("platform:ci13xxx_pci");
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 475c9c1..a5df24c 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -43,8 +43,7 @@
*
* TODO List
* - OTG
- * - Isochronous & Interrupt Traffic
- * - Handle requests which spawns into several TDs
+ * - Interrupt Traffic
* - GET_STATUS(device) - always reports 0
* - Gadget API (majority of optional features)
* - Suspend & Remote Wakeup
@@ -64,6 +63,8 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
+#include <linux/usb/of.h>
+#include <linux/phy.h>
#include "ci.h"
#include "udc.h"
@@ -116,7 +117,7 @@ static uintptr_t ci_regs_lpm[] = {
[OP_ENDPTCTRL] = 0x0ECUL,
};
-static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
+static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
{
int i;
@@ -148,7 +149,7 @@ static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
*
* This function returns an error code
*/
-int hw_port_test_set(struct ci13xxx *ci, u8 mode)
+int hw_port_test_set(struct ci_hdrc *ci, u8 mode)
{
const u8 TEST_MODE_MAX = 7;
@@ -164,12 +165,12 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
*
* This function returns port test mode value
*/
-u8 hw_port_test_get(struct ci13xxx *ci)
+u8 hw_port_test_get(struct ci_hdrc *ci)
{
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
-static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
+static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
{
u32 reg;
@@ -208,13 +209,52 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
return 0;
}
+static void hw_phymode_configure(struct ci_hdrc *ci)
+{
+ u32 portsc, lpm, sts;
+
+ switch (ci->platdata->phy_mode) {
+ case USBPHY_INTERFACE_MODE_UTMI:
+ portsc = PORTSC_PTS(PTS_UTMI);
+ lpm = DEVLC_PTS(PTS_UTMI);
+ break;
+ case USBPHY_INTERFACE_MODE_UTMIW:
+ portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW;
+ lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW;
+ break;
+ case USBPHY_INTERFACE_MODE_ULPI:
+ portsc = PORTSC_PTS(PTS_ULPI);
+ lpm = DEVLC_PTS(PTS_ULPI);
+ break;
+ case USBPHY_INTERFACE_MODE_SERIAL:
+ portsc = PORTSC_PTS(PTS_SERIAL);
+ lpm = DEVLC_PTS(PTS_SERIAL);
+ sts = 1;
+ break;
+ case USBPHY_INTERFACE_MODE_HSIC:
+ portsc = PORTSC_PTS(PTS_HSIC);
+ lpm = DEVLC_PTS(PTS_HSIC);
+ break;
+ default:
+ return;
+ }
+
+ if (ci->hw_bank.lpm) {
+ hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm);
+ hw_write(ci, OP_DEVLC, DEVLC_STS, sts);
+ } else {
+ hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc);
+ hw_write(ci, OP_PORTSC, PORTSC_STS, sts);
+ }
+}
+
/**
* hw_device_reset: resets chip (execute without interruption)
* @ci: the controller
*
* This function returns an error code
*/
-int hw_device_reset(struct ci13xxx *ci, u32 mode)
+int hw_device_reset(struct ci_hdrc *ci, u32 mode)
{
/* should flush & stop before reset */
hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
@@ -224,12 +264,13 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
while (hw_read(ci, OP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
+ hw_phymode_configure(ci);
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
- CI13XXX_CONTROLLER_RESET_EVENT);
+ CI_HDRC_CONTROLLER_RESET_EVENT);
- if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
+ if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
/* USBMODE should be configured step by step */
@@ -251,7 +292,7 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
* ci_otg_role - pick role based on ID pin state
* @ci: the controller
*/
-static enum ci_role ci_otg_role(struct ci13xxx *ci)
+static enum ci_role ci_otg_role(struct ci_hdrc *ci)
{
u32 sts = hw_read(ci, OP_OTGSC, ~0);
enum ci_role role = sts & OTGSC_ID
@@ -267,7 +308,7 @@ static enum ci_role ci_otg_role(struct ci13xxx *ci)
*/
static void ci_role_work(struct work_struct *work)
{
- struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
+ struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
enum ci_role role = ci_otg_role(ci);
if (role != ci->role) {
@@ -283,7 +324,7 @@ static void ci_role_work(struct work_struct *work)
static irqreturn_t ci_irq(int irq, void *data)
{
- struct ci13xxx *ci = data;
+ struct ci_hdrc *ci = data;
irqreturn_t ret = IRQ_NONE;
u32 otgsc = 0;
@@ -305,9 +346,9 @@ static irqreturn_t ci_irq(int irq, void *data)
static DEFINE_IDA(ci_ida);
-struct platform_device *ci13xxx_add_device(struct device *dev,
+struct platform_device *ci_hdrc_add_device(struct device *dev,
struct resource *res, int nres,
- struct ci13xxx_platform_data *platdata)
+ struct ci_hdrc_platform_data *platdata)
{
struct platform_device *pdev;
int id, ret;
@@ -347,29 +388,33 @@ put_id:
ida_simple_remove(&ci_ida, id);
return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(ci13xxx_add_device);
+EXPORT_SYMBOL_GPL(ci_hdrc_add_device);
-void ci13xxx_remove_device(struct platform_device *pdev)
+void ci_hdrc_remove_device(struct platform_device *pdev)
{
int id = pdev->id;
platform_device_unregister(pdev);
ida_simple_remove(&ci_ida, id);
}
-EXPORT_SYMBOL_GPL(ci13xxx_remove_device);
+EXPORT_SYMBOL_GPL(ci_hdrc_remove_device);
static int ci_hdrc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct ci13xxx *ci;
+ struct ci_hdrc *ci;
struct resource *res;
void __iomem *base;
int ret;
+ enum usb_dr_mode dr_mode;
if (!dev->platform_data) {
dev_err(dev, "platform data missing\n");
return -ENODEV;
}
+ if (!dev->of_node && dev->parent)
+ dev->of_node = dev->parent->of_node;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
@@ -409,14 +454,28 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (!ci->platdata->phy_mode)
+ ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
+
+ if (!ci->platdata->dr_mode)
+ ci->platdata->dr_mode = of_usb_get_dr_mode(dev->of_node);
+
+ if (ci->platdata->dr_mode == USB_DR_MODE_UNKNOWN)
+ ci->platdata->dr_mode = USB_DR_MODE_OTG;
+
+ dr_mode = ci->platdata->dr_mode;
/* initialize role(s) before the interrupt is requested */
- ret = ci_hdrc_host_init(ci);
- if (ret)
- dev_info(dev, "doesn't support host\n");
+ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
+ ret = ci_hdrc_host_init(ci);
+ if (ret)
+ dev_info(dev, "doesn't support host\n");
+ }
- ret = ci_hdrc_gadget_init(ci);
- if (ret)
- dev_info(dev, "doesn't support gadget\n");
+ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
+ ret = ci_hdrc_gadget_init(ci);
+ if (ret)
+ dev_info(dev, "doesn't support gadget\n");
+ }
if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
dev_err(dev, "no supported roles\n");
@@ -467,7 +526,7 @@ rm_wq:
static int ci_hdrc_remove(struct platform_device *pdev)
{
- struct ci13xxx *ci = platform_get_drvdata(pdev);
+ struct ci_hdrc *ci = platform_get_drvdata(pdev);
dbg_remove_files(ci);
flush_workqueue(ci->wq);
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 36a7063..96d899a 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -18,7 +18,7 @@
*/
static int ci_device_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = s->private;
+ struct ci_hdrc *ci = s->private;
struct usb_gadget *gadget = &ci->gadget;
seq_printf(s, "speed = %d\n", gadget->speed);
@@ -58,7 +58,7 @@ static const struct file_operations ci_device_fops = {
*/
static int ci_port_test_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = s->private;
+ struct ci_hdrc *ci = s->private;
unsigned long flags;
unsigned mode;
@@ -78,7 +78,7 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
- struct ci13xxx *ci = s->private;
+ struct ci_hdrc *ci = s->private;
unsigned long flags;
unsigned mode;
char buf[32];
@@ -115,7 +115,7 @@ static const struct file_operations ci_port_test_fops = {
*/
static int ci_qheads_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = s->private;
+ struct ci_hdrc *ci = s->private;
unsigned long flags;
unsigned i, j;
@@ -126,15 +126,15 @@ static int ci_qheads_show(struct seq_file *s, void *data)
spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max/2; i++) {
- struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
- struct ci13xxx_ep *mEpTx =
- &ci->ci13xxx_ep[i + ci->hw_ep_max/2];
+ struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i];
+ struct ci_hw_ep *hweptx =
+ &ci->ci_hw_ep[i + ci->hw_ep_max/2];
seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
- i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
- for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
+ i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma);
+ for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++)
seq_printf(s, " %04X: %08X %08X\n", j,
- *((u32 *)mEpRx->qh.ptr + j),
- *((u32 *)mEpTx->qh.ptr + j));
+ *((u32 *)hweprx->qh.ptr + j),
+ *((u32 *)hweptx->qh.ptr + j));
}
spin_unlock_irqrestore(&ci->lock, flags);
@@ -158,11 +158,12 @@ static const struct file_operations ci_qheads_fops = {
*/
static int ci_requests_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = s->private;
+ struct ci_hdrc *ci = s->private;
unsigned long flags;
struct list_head *ptr = NULL;
- struct ci13xxx_req *req = NULL;
- unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
+ struct ci_hw_req *req = NULL;
+ struct td_node *node, *tmpnode;
+ unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
if (ci->role != CI_ROLE_GADGET) {
seq_printf(s, "not in gadget mode\n");
@@ -171,16 +172,20 @@ static int ci_requests_show(struct seq_file *s, void *data)
spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max; i++)
- list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
- req = list_entry(ptr, struct ci13xxx_req, queue);
-
- seq_printf(s, "EP=%02i: TD=%08X %s\n",
- i % (ci->hw_ep_max / 2), (u32)req->dma,
- ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
-
- for (j = 0; j < qsize; j++)
- seq_printf(s, " %04X: %08X\n", j,
- *((u32 *)req->ptr + j));
+ list_for_each(ptr, &ci->ci_hw_ep[i].qh.queue) {
+ req = list_entry(ptr, struct ci_hw_req, queue);
+
+ list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
+ seq_printf(s, "EP=%02i: TD=%08X %s\n",
+ i % (ci->hw_ep_max / 2),
+ (u32)node->dma,
+ ((i < ci->hw_ep_max/2) ?
+ "RX" : "TX"));
+
+ for (j = 0; j < qsize; j++)
+ seq_printf(s, " %04X: %08X\n", j,
+ *((u32 *)node->ptr + j));
+ }
}
spin_unlock_irqrestore(&ci->lock, flags);
@@ -201,7 +206,7 @@ static const struct file_operations ci_requests_fops = {
static int ci_role_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = s->private;
+ struct ci_hdrc *ci = s->private;
seq_printf(s, "%s\n", ci_role(ci)->name);
@@ -212,7 +217,7 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
- struct ci13xxx *ci = s->private;
+ struct ci_hdrc *ci = s->private;
enum ci_role role;
char buf[8];
int ret;
@@ -254,7 +259,7 @@ static const struct file_operations ci_role_fops = {
*
* This function returns an error code
*/
-int dbg_create_files(struct ci13xxx *ci)
+int dbg_create_files(struct ci_hdrc *ci)
{
struct dentry *dent;
@@ -295,7 +300,7 @@ err:
* dbg_remove_files: destroys the attribute interface
* @ci: device
*/
-void dbg_remove_files(struct ci13xxx *ci)
+void dbg_remove_files(struct ci_hdrc *ci)
{
debugfs_remove_recursive(ci->debugfs);
}
diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h
index 7ca6ca0..e16478c 100644
--- a/drivers/usb/chipidea/debug.h
+++ b/drivers/usb/chipidea/debug.h
@@ -14,15 +14,15 @@
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
-int dbg_create_files(struct ci13xxx *ci);
-void dbg_remove_files(struct ci13xxx *ci);
+int dbg_create_files(struct ci_hdrc *ci);
+void dbg_remove_files(struct ci_hdrc *ci);
#else
-static inline int dbg_create_files(struct ci13xxx *ci)
+static inline int dbg_create_files(struct ci_hdrc *ci)
{
return 0;
}
-static inline void dbg_remove_files(struct ci13xxx *ci)
+static inline void dbg_remove_files(struct ci_hdrc *ci)
{
}
#endif
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 8e9d312..40d0fda 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -33,12 +33,12 @@
static struct hc_driver __read_mostly ci_ehci_hc_driver;
-static irqreturn_t host_irq(struct ci13xxx *ci)
+static irqreturn_t host_irq(struct ci_hdrc *ci)
{
return usb_hcd_irq(ci->irq, ci->hcd);
}
-static int host_start(struct ci13xxx *ci)
+static int host_start(struct ci_hdrc *ci)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
@@ -70,13 +70,13 @@ static int host_start(struct ci13xxx *ci)
else
ci->hcd = hcd;
- if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
+ if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
return ret;
}
-static void host_stop(struct ci13xxx *ci)
+static void host_stop(struct ci_hdrc *ci)
{
struct usb_hcd *hcd = ci->hcd;
@@ -84,7 +84,7 @@ static void host_stop(struct ci13xxx *ci)
usb_put_hcd(hcd);
}
-int ci_hdrc_host_init(struct ci13xxx *ci)
+int ci_hdrc_host_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
index 761fb1f..058875c 100644
--- a/drivers/usb/chipidea/host.h
+++ b/drivers/usb/chipidea/host.h
@@ -3,11 +3,11 @@
#ifdef CONFIG_USB_CHIPIDEA_HOST
-int ci_hdrc_host_init(struct ci13xxx *ci);
+int ci_hdrc_host_init(struct ci_hdrc *ci);
#else
-static inline int ci_hdrc_host_init(struct ci13xxx *ci)
+static inline int ci_hdrc_host_init(struct ci_hdrc *ci)
{
return -ENXIO;
}
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index b501346..e475fcd 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -61,7 +61,7 @@ static inline int hw_ep_bit(int num, int dir)
return num + (dir ? 16 : 0);
}
-static inline int ep_to_bit(struct ci13xxx *ci, int n)
+static inline int ep_to_bit(struct ci_hdrc *ci, int n)
{
int fill = 16 - ci->hw_ep_max / 2;
@@ -77,7 +77,7 @@ static inline int ep_to_bit(struct ci13xxx *ci, int n)
*
* This function returns an error code
*/
-static int hw_device_state(struct ci13xxx *ci, u32 dma)
+static int hw_device_state(struct ci_hdrc *ci, u32 dma)
{
if (dma) {
hw_write(ci, OP_ENDPTLISTADDR, ~0, dma);
@@ -97,7 +97,7 @@ static int hw_device_state(struct ci13xxx *ci, u32 dma)
*
* This function returns an error code
*/
-static int hw_ep_flush(struct ci13xxx *ci, int num, int dir)
+static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)
{
int n = hw_ep_bit(num, dir);
@@ -118,7 +118,7 @@ static int hw_ep_flush(struct ci13xxx *ci, int num, int dir)
*
* This function returns an error code
*/
-static int hw_ep_disable(struct ci13xxx *ci, int num, int dir)
+static int hw_ep_disable(struct ci_hdrc *ci, int num, int dir)
{
hw_ep_flush(ci, num, dir);
hw_write(ci, OP_ENDPTCTRL + num,
@@ -134,7 +134,7 @@ static int hw_ep_disable(struct ci13xxx *ci, int num, int dir)
*
* This function returns an error code
*/
-static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
+static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type)
{
u32 mask, data;
@@ -168,7 +168,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
*
* This function returns 1 if endpoint halted
*/
-static int hw_ep_get_halt(struct ci13xxx *ci, int num, int dir)
+static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir)
{
u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
@@ -182,7 +182,7 @@ static int hw_ep_get_halt(struct ci13xxx *ci, int num, int dir)
*
* This function returns setup status
*/
-static int hw_test_and_clear_setup_status(struct ci13xxx *ci, int n)
+static int hw_test_and_clear_setup_status(struct ci_hdrc *ci, int n)
{
n = ep_to_bit(ci, n);
return hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(n));
@@ -196,7 +196,7 @@ static int hw_test_and_clear_setup_status(struct ci13xxx *ci, int n)
*
* This function returns an error code
*/
-static int hw_ep_prime(struct ci13xxx *ci, int num, int dir, int is_ctrl)
+static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
{
int n = hw_ep_bit(num, dir);
@@ -223,13 +223,13 @@ static int hw_ep_prime(struct ci13xxx *ci, int num, int dir, int is_ctrl)
*
* This function returns an error code
*/
-static int hw_ep_set_halt(struct ci13xxx *ci, int num, int dir, int value)
+static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value)
{
if (value != 0 && value != 1)
return -EINVAL;
do {
- enum ci13xxx_regs reg = OP_ENDPTCTRL + num;
+ enum ci_hw_regs reg = OP_ENDPTCTRL + num;
u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
@@ -246,7 +246,7 @@ static int hw_ep_set_halt(struct ci13xxx *ci, int num, int dir, int value)
*
* This function returns true if high speed port
*/
-static int hw_port_is_high_speed(struct ci13xxx *ci)
+static int hw_port_is_high_speed(struct ci_hdrc *ci)
{
return ci->hw_bank.lpm ? hw_read(ci, OP_DEVLC, DEVLC_PSPD) :
hw_read(ci, OP_PORTSC, PORTSC_HSP);
@@ -257,7 +257,7 @@ static int hw_port_is_high_speed(struct ci13xxx *ci)
*
* This function returns register data
*/
-static u32 hw_read_intr_enable(struct ci13xxx *ci)
+static u32 hw_read_intr_enable(struct ci_hdrc *ci)
{
return hw_read(ci, OP_USBINTR, ~0);
}
@@ -267,7 +267,7 @@ static u32 hw_read_intr_enable(struct ci13xxx *ci)
*
* This function returns register data
*/
-static u32 hw_read_intr_status(struct ci13xxx *ci)
+static u32 hw_read_intr_status(struct ci_hdrc *ci)
{
return hw_read(ci, OP_USBSTS, ~0);
}
@@ -279,7 +279,7 @@ static u32 hw_read_intr_status(struct ci13xxx *ci)
*
* This function returns complete status
*/
-static int hw_test_and_clear_complete(struct ci13xxx *ci, int n)
+static int hw_test_and_clear_complete(struct ci_hdrc *ci, int n)
{
n = ep_to_bit(ci, n);
return hw_test_and_clear(ci, OP_ENDPTCOMPLETE, BIT(n));
@@ -291,7 +291,7 @@ static int hw_test_and_clear_complete(struct ci13xxx *ci, int n)
*
* This function returns active interrutps
*/
-static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
+static u32 hw_test_and_clear_intr_active(struct ci_hdrc *ci)
{
u32 reg = hw_read_intr_status(ci) & hw_read_intr_enable(ci);
@@ -305,7 +305,7 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
*
* This function returns guard value
*/
-static int hw_test_and_clear_setup_guard(struct ci13xxx *ci)
+static int hw_test_and_clear_setup_guard(struct ci_hdrc *ci)
{
return hw_test_and_write(ci, OP_USBCMD, USBCMD_SUTW, 0);
}
@@ -316,7 +316,7 @@ static int hw_test_and_clear_setup_guard(struct ci13xxx *ci)
*
* This function returns guard value
*/
-static int hw_test_and_set_setup_guard(struct ci13xxx *ci)
+static int hw_test_and_set_setup_guard(struct ci_hdrc *ci)
{
return hw_test_and_write(ci, OP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
}
@@ -328,7 +328,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci)
* This function explicitly sets the address, without the "USBADRA" (advance)
* feature, which is not supported by older versions of the controller.
*/
-static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
+static void hw_usb_set_address(struct ci_hdrc *ci, u8 value)
{
hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
value << __ffs(DEVICEADDR_USBADR));
@@ -340,7 +340,7 @@ static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
*
* This function returns an error code
*/
-static int hw_usb_reset(struct ci13xxx *ci)
+static int hw_usb_reset(struct ci_hdrc *ci)
{
hw_usb_set_address(ci, 0);
@@ -368,11 +368,60 @@ static int hw_usb_reset(struct ci13xxx *ci)
/******************************************************************************
* UTIL block
*****************************************************************************/
+
+static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
+ unsigned length)
+{
+ int i;
+ u32 temp;
+ struct td_node *lastnode, *node = kzalloc(sizeof(struct td_node),
+ GFP_ATOMIC);
+
+ if (node == NULL)
+ return -ENOMEM;
+
+ node->ptr = dma_pool_alloc(hwep->td_pool, GFP_ATOMIC,
+ &node->dma);
+ if (node->ptr == NULL) {
+ kfree(node);
+ return -ENOMEM;
+ }
+
+ memset(node->ptr, 0, sizeof(struct ci_hw_td));
+ node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
+ node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
+ node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
+
+ temp = (u32) (hwreq->req.dma + hwreq->req.actual);
+ if (length) {
+ node->ptr->page[0] = cpu_to_le32(temp);
+ for (i = 1; i < TD_PAGE_COUNT; i++) {
+ u32 page = temp + i * CI_HDRC_PAGE_SIZE;
+ page &= ~TD_RESERVED_MASK;
+ node->ptr->page[i] = cpu_to_le32(page);
+ }
+ }
+
+ hwreq->req.actual += length;
+
+ if (!list_empty(&hwreq->tds)) {
+ /* get the last entry */
+ lastnode = list_entry(hwreq->tds.prev,
+ struct td_node, td);
+ lastnode->ptr->next = cpu_to_le32(node->dma);
+ }
+
+ INIT_LIST_HEAD(&node->td);
+ list_add_tail(&node->td, &hwreq->tds);
+
+ return 0;
+}
+
/**
* _usb_addr: calculates endpoint address from direction & number
* @ep: endpoint
*/
-static inline u8 _usb_addr(struct ci13xxx_ep *ep)
+static inline u8 _usb_addr(struct ci_hw_ep *ep)
{
return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
}
@@ -380,75 +429,73 @@ static inline u8 _usb_addr(struct ci13xxx_ep *ep)
/**
* _hardware_queue: configures a request at hardware level
* @gadget: gadget
- * @mEp: endpoint
+ * @hwep: endpoint
*
* This function returns an error code
*/
-static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
{
- struct ci13xxx *ci = mEp->ci;
- unsigned i;
+ struct ci_hdrc *ci = hwep->ci;
int ret = 0;
- unsigned length = mReq->req.length;
+ unsigned rest = hwreq->req.length;
+ int pages = TD_PAGE_COUNT;
+ struct td_node *firstnode, *lastnode;
/* don't queue twice */
- if (mReq->req.status == -EALREADY)
+ if (hwreq->req.status == -EALREADY)
return -EALREADY;
- mReq->req.status = -EALREADY;
-
- if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
- mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
- &mReq->zdma);
- if (mReq->zptr == NULL)
- return -ENOMEM;
+ hwreq->req.status = -EALREADY;
- memset(mReq->zptr, 0, sizeof(*mReq->zptr));
- mReq->zptr->next = cpu_to_le32(TD_TERMINATE);
- mReq->zptr->token = cpu_to_le32(TD_STATUS_ACTIVE);
- if (!mReq->req.no_interrupt)
- mReq->zptr->token |= cpu_to_le32(TD_IOC);
- }
- ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);
+ ret = usb_gadget_map_request(&ci->gadget, &hwreq->req, hwep->dir);
if (ret)
return ret;
/*
- * TD configuration
- * TODO - handle requests which spawns into several TDs
+ * The first buffer could be not page aligned.
+ * In that case we have to span into one extra td.
*/
- memset(mReq->ptr, 0, sizeof(*mReq->ptr));
- mReq->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
- mReq->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
- mReq->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
- if (mReq->zptr) {
- mReq->ptr->next = cpu_to_le32(mReq->zdma);
- } else {
- mReq->ptr->next = cpu_to_le32(TD_TERMINATE);
- if (!mReq->req.no_interrupt)
- mReq->ptr->token |= cpu_to_le32(TD_IOC);
- }
- mReq->ptr->page[0] = cpu_to_le32(mReq->req.dma);
- for (i = 1; i < TD_PAGE_COUNT; i++) {
- u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE;
- page &= ~TD_RESERVED_MASK;
- mReq->ptr->page[i] = cpu_to_le32(page);
+ if (hwreq->req.dma % PAGE_SIZE)
+ pages--;
+
+ if (rest == 0)
+ add_td_to_list(hwep, hwreq, 0);
+
+ while (rest > 0) {
+ unsigned count = min(hwreq->req.length - hwreq->req.actual,
+ (unsigned)(pages * CI_HDRC_PAGE_SIZE));
+ add_td_to_list(hwep, hwreq, count);
+ rest -= count;
}
+ if (hwreq->req.zero && hwreq->req.length
+ && (hwreq->req.length % hwep->ep.maxpacket == 0))
+ add_td_to_list(hwep, hwreq, 0);
+
+ firstnode = list_first_entry(&hwreq->tds, struct td_node, td);
+
+ lastnode = list_entry(hwreq->tds.prev,
+ struct td_node, td);
+
+ lastnode->ptr->next = cpu_to_le32(TD_TERMINATE);
+ if (!hwreq->req.no_interrupt)
+ lastnode->ptr->token |= cpu_to_le32(TD_IOC);
wmb();
- if (!list_empty(&mEp->qh.queue)) {
- struct ci13xxx_req *mReqPrev;
- int n = hw_ep_bit(mEp->num, mEp->dir);
+ hwreq->req.actual = 0;
+ if (!list_empty(&hwep->qh.queue)) {
+ struct ci_hw_req *hwreqprev;
+ int n = hw_ep_bit(hwep->num, hwep->dir);
int tmp_stat;
- u32 next = mReq->dma & TD_ADDR_MASK;
-
- mReqPrev = list_entry(mEp->qh.queue.prev,
- struct ci13xxx_req, queue);
- if (mReqPrev->zptr)
- mReqPrev->zptr->next = cpu_to_le32(next);
- else
- mReqPrev->ptr->next = cpu_to_le32(next);
+ struct td_node *prevlastnode;
+ u32 next = firstnode->dma & TD_ADDR_MASK;
+
+ hwreqprev = list_entry(hwep->qh.queue.prev,
+ struct ci_hw_req, queue);
+ prevlastnode = list_entry(hwreqprev->tds.prev,
+ struct td_node, td);
+
+ prevlastnode->ptr->next = cpu_to_le32(next);
wmb();
if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
goto done;
@@ -462,99 +509,152 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
}
/* QH configuration */
- mEp->qh.ptr->td.next = cpu_to_le32(mReq->dma); /* TERMINATE = 0 */
- mEp->qh.ptr->td.token &=
+ hwep->qh.ptr->td.next = cpu_to_le32(firstnode->dma);
+ hwep->qh.ptr->td.token &=
cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
+ if (hwep->type == USB_ENDPOINT_XFER_ISOC) {
+ u32 mul = hwreq->req.length / hwep->ep.maxpacket;
+
+ if (hwreq->req.length % hwep->ep.maxpacket)
+ mul++;
+ hwep->qh.ptr->cap |= mul << __ffs(QH_MULT);
+ }
+
wmb(); /* synchronize before ep prime */
- ret = hw_ep_prime(ci, mEp->num, mEp->dir,
- mEp->type == USB_ENDPOINT_XFER_CONTROL);
+ ret = hw_ep_prime(ci, hwep->num, hwep->dir,
+ hwep->type == USB_ENDPOINT_XFER_CONTROL);
done:
return ret;
}
+/*
+ * free_pending_td: remove a pending request for the endpoint
+ * @hwep: endpoint
+ */
+static void free_pending_td(struct ci_hw_ep *hwep)
+{
+ struct td_node *pending = hwep->pending_td;
+
+ dma_pool_free(hwep->td_pool, pending->ptr, pending->dma);
+ hwep->pending_td = NULL;
+ kfree(pending);
+}
+
/**
* _hardware_dequeue: handles a request at hardware level
* @gadget: gadget
- * @mEp: endpoint
+ * @hwep: endpoint
*
* This function returns an error code
*/
-static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
{
- u32 tmptoken = le32_to_cpu(mReq->ptr->token);
+ u32 tmptoken;
+ struct td_node *node, *tmpnode;
+ unsigned remaining_length;
+ unsigned actual = hwreq->req.length;
- if (mReq->req.status != -EALREADY)
+ if (hwreq->req.status != -EALREADY)
return -EINVAL;
- if ((TD_STATUS_ACTIVE & tmptoken) != 0)
- return -EBUSY;
+ hwreq->req.status = 0;
- if (mReq->zptr) {
- if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)
+ list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
+ tmptoken = le32_to_cpu(node->ptr->token);
+ if ((TD_STATUS_ACTIVE & tmptoken) != 0) {
+ hwreq->req.status = -EALREADY;
return -EBUSY;
- dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
- mReq->zptr = NULL;
- }
+ }
- mReq->req.status = 0;
+ remaining_length = (tmptoken & TD_TOTAL_BYTES);
+ remaining_length >>= __ffs(TD_TOTAL_BYTES);
+ actual -= remaining_length;
+
+ hwreq->req.status = tmptoken & TD_STATUS;
+ if ((TD_STATUS_HALTED & hwreq->req.status)) {
+ hwreq->req.status = -EPIPE;
+ break;
+ } else if ((TD_STATUS_DT_ERR & hwreq->req.status)) {
+ hwreq->req.status = -EPROTO;
+ break;
+ } else if ((TD_STATUS_TR_ERR & hwreq->req.status)) {
+ hwreq->req.status = -EILSEQ;
+ break;
+ }
- usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir);
+ if (remaining_length) {
+ if (hwep->dir) {
+ hwreq->req.status = -EPROTO;
+ break;
+ }
+ }
+ /*
+ * As the hardware could still address the freed td
+ * which will run the udc unusable, the cleanup of the
+ * td has to be delayed by one.
+ */
+ if (hwep->pending_td)
+ free_pending_td(hwep);
- mReq->req.status = tmptoken & TD_STATUS;
- if ((TD_STATUS_HALTED & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
+ hwep->pending_td = node;
+ list_del_init(&node->td);
+ }
- mReq->req.actual = tmptoken & TD_TOTAL_BYTES;
- mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);
- mReq->req.actual = mReq->req.length - mReq->req.actual;
- mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
+ usb_gadget_unmap_request(&hwep->ci->gadget, &hwreq->req, hwep->dir);
- return mReq->req.actual;
+ hwreq->req.actual += actual;
+
+ if (hwreq->req.status)
+ return hwreq->req.status;
+
+ return hwreq->req.actual;
}
/**
* _ep_nuke: dequeues all endpoint requests
- * @mEp: endpoint
+ * @hwep: endpoint
*
* This function returns an error code
* Caller must hold lock
*/
-static int _ep_nuke(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
+static int _ep_nuke(struct ci_hw_ep *hwep)
+__releases(hwep->lock)
+__acquires(hwep->lock)
{
- if (mEp == NULL)
+ struct td_node *node, *tmpnode;
+ if (hwep == NULL)
return -EINVAL;
- hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
+ hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
- while (!list_empty(&mEp->qh.queue)) {
+ while (!list_empty(&hwep->qh.queue)) {
/* pop oldest request */
- struct ci13xxx_req *mReq = \
- list_entry(mEp->qh.queue.next,
- struct ci13xxx_req, queue);
-
- if (mReq->zptr) {
- dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
- mReq->zptr = NULL;
+ struct ci_hw_req *hwreq = list_entry(hwep->qh.queue.next,
+ struct ci_hw_req, queue);
+
+ list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
+ dma_pool_free(hwep->td_pool, node->ptr, node->dma);
+ list_del_init(&node->td);
+ node->ptr = NULL;
+ kfree(node);
}
- list_del_init(&mReq->queue);
- mReq->req.status = -ESHUTDOWN;
+ list_del_init(&hwreq->queue);
+ hwreq->req.status = -ESHUTDOWN;
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- mReq->req.complete(&mEp->ep, &mReq->req);
- spin_lock(mEp->lock);
+ if (hwreq->req.complete != NULL) {
+ spin_unlock(hwep->lock);
+ hwreq->req.complete(&hwep->ep, &hwreq->req);
+ spin_lock(hwep->lock);
}
}
+
+ if (hwep->pending_td)
+ free_pending_td(hwep);
+
return 0;
}
@@ -567,7 +667,7 @@ __acquires(mEp->lock)
static int _gadget_stop_activity(struct usb_gadget *gadget)
{
struct usb_ep *ep;
- struct ci13xxx *ci = container_of(gadget, struct ci13xxx, gadget);
+ struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
unsigned long flags;
spin_lock_irqsave(&ci->lock, flags);
@@ -608,7 +708,7 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
*
* This function resets USB engine after a bus reset occurred
*/
-static void isr_reset_handler(struct ci13xxx *ci)
+static void isr_reset_handler(struct ci_hdrc *ci)
__releases(ci->lock)
__acquires(ci->lock)
{
@@ -658,47 +758,48 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- struct ci13xxx *ci = mEp->ci;
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
+ struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
+ struct ci_hdrc *ci = hwep->ci;
int retval = 0;
- if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ if (ep == NULL || req == NULL || hwep->ep.desc == NULL)
return -EINVAL;
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (hwep->type == USB_ENDPOINT_XFER_CONTROL) {
if (req->length)
- mEp = (ci->ep0_dir == RX) ?
+ hwep = (ci->ep0_dir == RX) ?
ci->ep0out : ci->ep0in;
- if (!list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
+ if (!list_empty(&hwep->qh.queue)) {
+ _ep_nuke(hwep);
retval = -EOVERFLOW;
- dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
- _usb_addr(mEp));
+ dev_warn(hwep->ci->dev, "endpoint ctrl %X nuked\n",
+ _usb_addr(hwep));
}
}
- /* first nuke then test link, e.g. previous status has not sent */
- if (!list_empty(&mReq->queue)) {
- dev_err(mEp->ci->dev, "request already in queue\n");
- return -EBUSY;
+ if (usb_endpoint_xfer_isoc(hwep->ep.desc) &&
+ hwreq->req.length > (1 + hwep->ep.mult) * hwep->ep.maxpacket) {
+ dev_err(hwep->ci->dev, "request length too big for isochronous\n");
+ return -EMSGSIZE;
}
- if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) {
- dev_err(mEp->ci->dev, "request bigger than one td\n");
- return -EMSGSIZE;
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&hwreq->queue)) {
+ dev_err(hwep->ci->dev, "request already in queue\n");
+ return -EBUSY;
}
/* push request */
- mReq->req.status = -EINPROGRESS;
- mReq->req.actual = 0;
+ hwreq->req.status = -EINPROGRESS;
+ hwreq->req.actual = 0;
- retval = _hardware_enqueue(mEp, mReq);
+ retval = _hardware_enqueue(hwep, hwreq);
if (retval == -EALREADY)
retval = 0;
if (!retval)
- list_add_tail(&mReq->queue, &mEp->qh.queue);
+ list_add_tail(&hwreq->queue, &hwep->qh.queue);
return retval;
}
@@ -710,22 +811,22 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
*
* This function returns an error code
*/
-static int isr_get_status_response(struct ci13xxx *ci,
+static int isr_get_status_response(struct ci_hdrc *ci,
struct usb_ctrlrequest *setup)
-__releases(mEp->lock)
-__acquires(mEp->lock)
+__releases(hwep->lock)
+__acquires(hwep->lock)
{
- struct ci13xxx_ep *mEp = ci->ep0in;
+ struct ci_hw_ep *hwep = ci->ep0in;
struct usb_request *req = NULL;
gfp_t gfp_flags = GFP_ATOMIC;
int dir, num, retval;
- if (mEp == NULL || setup == NULL)
+ if (hwep == NULL || setup == NULL)
return -EINVAL;
- spin_unlock(mEp->lock);
- req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
- spin_lock(mEp->lock);
+ spin_unlock(hwep->lock);
+ req = usb_ep_alloc_request(&hwep->ep, gfp_flags);
+ spin_lock(hwep->lock);
if (req == NULL)
return -ENOMEM;
@@ -750,7 +851,7 @@ __acquires(mEp->lock)
}
/* else do nothing; reserved for future use */
- retval = _ep_queue(&mEp->ep, req, gfp_flags);
+ retval = _ep_queue(&hwep->ep, req, gfp_flags);
if (retval)
goto err_free_buf;
@@ -759,9 +860,9 @@ __acquires(mEp->lock)
err_free_buf:
kfree(req->buf);
err_free_req:
- spin_unlock(mEp->lock);
- usb_ep_free_request(&mEp->ep, req);
- spin_lock(mEp->lock);
+ spin_unlock(hwep->lock);
+ usb_ep_free_request(&hwep->ep, req);
+ spin_lock(hwep->lock);
return retval;
}
@@ -776,7 +877,7 @@ __acquires(mEp->lock)
static void
isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct ci13xxx *ci = req->context;
+ struct ci_hdrc *ci = req->context;
unsigned long flags;
if (ci->setaddr) {
@@ -796,48 +897,48 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
*
* This function returns an error code
*/
-static int isr_setup_status_phase(struct ci13xxx *ci)
+static int isr_setup_status_phase(struct ci_hdrc *ci)
{
int retval;
- struct ci13xxx_ep *mEp;
+ struct ci_hw_ep *hwep;
- mEp = (ci->ep0_dir == TX) ? ci->ep0out : ci->ep0in;
+ hwep = (ci->ep0_dir == TX) ? ci->ep0out : ci->ep0in;
ci->status->context = ci;
ci->status->complete = isr_setup_status_complete;
- retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
+ retval = _ep_queue(&hwep->ep, ci->status, GFP_ATOMIC);
return retval;
}
/**
* isr_tr_complete_low: transaction complete low level handler
- * @mEp: endpoint
+ * @hwep: endpoint
*
* This function returns an error code
* Caller must hold lock
*/
-static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
+static int isr_tr_complete_low(struct ci_hw_ep *hwep)
+__releases(hwep->lock)
+__acquires(hwep->lock)
{
- struct ci13xxx_req *mReq, *mReqTemp;
- struct ci13xxx_ep *mEpTemp = mEp;
+ struct ci_hw_req *hwreq, *hwreqtemp;
+ struct ci_hw_ep *hweptemp = hwep;
int retval = 0;
- list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
+ list_for_each_entry_safe(hwreq, hwreqtemp, &hwep->qh.queue,
queue) {
- retval = _hardware_dequeue(mEp, mReq);
+ retval = _hardware_dequeue(hwep, hwreq);
if (retval < 0)
break;
- list_del_init(&mReq->queue);
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
- mReq->req.length)
- mEpTemp = mEp->ci->ep0in;
- mReq->req.complete(&mEpTemp->ep, &mReq->req);
- spin_lock(mEp->lock);
+ list_del_init(&hwreq->queue);
+ if (hwreq->req.complete != NULL) {
+ spin_unlock(hwep->lock);
+ if ((hwep->type == USB_ENDPOINT_XFER_CONTROL) &&
+ hwreq->req.length)
+ hweptemp = hwep->ci->ep0in;
+ hwreq->req.complete(&hweptemp->ep, &hwreq->req);
+ spin_lock(hwep->lock);
}
}
@@ -853,7 +954,7 @@ __acquires(mEp->lock)
*
* This function handles traffic events
*/
-static void isr_tr_complete_handler(struct ci13xxx *ci)
+static void isr_tr_complete_handler(struct ci_hdrc *ci)
__releases(ci->lock)
__acquires(ci->lock)
{
@@ -861,21 +962,21 @@ __acquires(ci->lock)
u8 tmode = 0;
for (i = 0; i < ci->hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
+ struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
int type, num, dir, err = -EINVAL;
struct usb_ctrlrequest req;
- if (mEp->ep.desc == NULL)
+ if (hwep->ep.desc == NULL)
continue; /* not configured */
if (hw_test_and_clear_complete(ci, i)) {
- err = isr_tr_complete_low(mEp);
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ err = isr_tr_complete_low(hwep);
+ if (hwep->type == USB_ENDPOINT_XFER_CONTROL) {
if (err > 0) /* needs status phase */
err = isr_setup_status_phase(ci);
if (err < 0) {
spin_unlock(&ci->lock);
- if (usb_ep_set_halt(&mEp->ep))
+ if (usb_ep_set_halt(&hwep->ep))
dev_err(ci->dev,
"error: ep_set_halt\n");
spin_lock(&ci->lock);
@@ -883,7 +984,7 @@ __acquires(ci->lock)
}
}
- if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
+ if (hwep->type != USB_ENDPOINT_XFER_CONTROL ||
!hw_test_and_clear_setup_status(ci, i))
continue;
@@ -902,7 +1003,7 @@ __acquires(ci->lock)
/* read_setup_packet */
do {
hw_test_and_set_setup_guard(ci);
- memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
+ memcpy(&req, &hwep->qh.ptr->setup, sizeof(req));
} while (!hw_test_and_clear_setup_guard(ci));
type = req.bRequestType;
@@ -921,10 +1022,10 @@ __acquires(ci->lock)
num &= USB_ENDPOINT_NUMBER_MASK;
if (dir) /* TX */
num += ci->hw_ep_max/2;
- if (!ci->ci13xxx_ep[num].wedge) {
+ if (!ci->ci_hw_ep[num].wedge) {
spin_unlock(&ci->lock);
err = usb_ep_clear_halt(
- &ci->ci13xxx_ep[num].ep);
+ &ci->ci_hw_ep[num].ep);
spin_lock(&ci->lock);
if (err)
break;
@@ -974,7 +1075,7 @@ __acquires(ci->lock)
num += ci->hw_ep_max/2;
spin_unlock(&ci->lock);
- err = usb_ep_set_halt(&ci->ci13xxx_ep[num].ep);
+ err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep);
spin_lock(&ci->lock);
if (!err)
isr_setup_status_phase(ci);
@@ -1021,7 +1122,7 @@ delegate:
if (err < 0) {
spin_unlock(&ci->lock);
- if (usb_ep_set_halt(&mEp->ep))
+ if (usb_ep_set_halt(&hwep->ep))
dev_err(ci->dev, "error: ep_set_halt\n");
spin_lock(&ci->lock);
}
@@ -1039,7 +1140,7 @@ delegate:
static int ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
int retval = 0;
unsigned long flags;
u32 cap = 0;
@@ -1047,39 +1148,41 @@ static int ep_enable(struct usb_ep *ep,
if (ep == NULL || desc == NULL)
return -EINVAL;
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(hwep->lock, flags);
/* only internal SW should enable ctrl endpts */
- mEp->ep.desc = desc;
+ hwep->ep.desc = desc;
- if (!list_empty(&mEp->qh.queue))
- dev_warn(mEp->ci->dev, "enabling a non-empty endpoint!\n");
+ if (!list_empty(&hwep->qh.queue))
+ dev_warn(hwep->ci->dev, "enabling a non-empty endpoint!\n");
- mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX;
- mEp->num = usb_endpoint_num(desc);
- mEp->type = usb_endpoint_type(desc);
+ hwep->dir = usb_endpoint_dir_in(desc) ? TX : RX;
+ hwep->num = usb_endpoint_num(desc);
+ hwep->type = usb_endpoint_type(desc);
- mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+ hwep->ep.maxpacket = usb_endpoint_maxp(desc) & 0x07ff;
+ hwep->ep.mult = QH_ISO_MULT(usb_endpoint_maxp(desc));
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
cap |= QH_IOS;
- if (mEp->num)
+ if (hwep->num)
cap |= QH_ZLT;
- cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
+ cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
- mEp->qh.ptr->cap = cpu_to_le32(cap);
+ hwep->qh.ptr->cap = cpu_to_le32(cap);
- mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
+ hwep->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
/*
* Enable endpoints in the HW other than ep0 as ep0
* is always enabled
*/
- if (mEp->num)
- retval |= hw_ep_enable(mEp->ci, mEp->num, mEp->dir, mEp->type);
+ if (hwep->num)
+ retval |= hw_ep_enable(hwep->ci, hwep->num, hwep->dir,
+ hwep->type);
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
return retval;
}
@@ -1090,32 +1193,32 @@ static int ep_enable(struct usb_ep *ep,
*/
static int ep_disable(struct usb_ep *ep)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
int direction, retval = 0;
unsigned long flags;
if (ep == NULL)
return -EINVAL;
- else if (mEp->ep.desc == NULL)
+ else if (hwep->ep.desc == NULL)
return -EBUSY;
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(hwep->lock, flags);
/* only internal SW should disable ctrl endpts */
- direction = mEp->dir;
+ direction = hwep->dir;
do {
- retval |= _ep_nuke(mEp);
- retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir);
+ retval |= _ep_nuke(hwep);
+ retval |= hw_ep_disable(hwep->ci, hwep->num, hwep->dir);
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->dir = (mEp->dir == TX) ? RX : TX;
+ if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
+ hwep->dir = (hwep->dir == TX) ? RX : TX;
- } while (mEp->dir != direction);
+ } while (hwep->dir != direction);
- mEp->ep.desc = NULL;
+ hwep->ep.desc = NULL;
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
return retval;
}
@@ -1126,25 +1229,18 @@ static int ep_disable(struct usb_ep *ep)
*/
static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = NULL;
+ struct ci_hw_req *hwreq = NULL;
if (ep == NULL)
return NULL;
- mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
- if (mReq != NULL) {
- INIT_LIST_HEAD(&mReq->queue);
-
- mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
- &mReq->dma);
- if (mReq->ptr == NULL) {
- kfree(mReq);
- mReq = NULL;
- }
+ hwreq = kzalloc(sizeof(struct ci_hw_req), gfp_flags);
+ if (hwreq != NULL) {
+ INIT_LIST_HEAD(&hwreq->queue);
+ INIT_LIST_HEAD(&hwreq->tds);
}
- return (mReq == NULL) ? NULL : &mReq->req;
+ return (hwreq == NULL) ? NULL : &hwreq->req;
}
/**
@@ -1154,24 +1250,30 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
*/
static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
+ struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
+ struct td_node *node, *tmpnode;
unsigned long flags;
if (ep == NULL || req == NULL) {
return;
- } else if (!list_empty(&mReq->queue)) {
- dev_err(mEp->ci->dev, "freeing queued request\n");
+ } else if (!list_empty(&hwreq->queue)) {
+ dev_err(hwep->ci->dev, "freeing queued request\n");
return;
}
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(hwep->lock, flags);
- if (mReq->ptr)
- dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
- kfree(mReq);
+ list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
+ dma_pool_free(hwep->td_pool, node->ptr, node->dma);
+ list_del_init(&node->td);
+ node->ptr = NULL;
+ kfree(node);
+ }
+
+ kfree(hwreq);
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
}
/**
@@ -1182,16 +1284,16 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
static int ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
int retval = 0;
unsigned long flags;
- if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ if (ep == NULL || req == NULL || hwep->ep.desc == NULL)
return -EINVAL;
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(hwep->lock, flags);
retval = _ep_queue(ep, req, gfp_flags);
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
return retval;
}
@@ -1202,33 +1304,33 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
*/
static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
+ struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
unsigned long flags;
- if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
- mEp->ep.desc == NULL || list_empty(&mReq->queue) ||
- list_empty(&mEp->qh.queue))
+ if (ep == NULL || req == NULL || hwreq->req.status != -EALREADY ||
+ hwep->ep.desc == NULL || list_empty(&hwreq->queue) ||
+ list_empty(&hwep->qh.queue))
return -EINVAL;
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(hwep->lock, flags);
- hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
+ hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
/* pop request */
- list_del_init(&mReq->queue);
+ list_del_init(&hwreq->queue);
- usb_gadget_unmap_request(&mEp->ci->gadget, req, mEp->dir);
+ usb_gadget_unmap_request(&hwep->ci->gadget, req, hwep->dir);
req->status = -ECONNRESET;
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- mReq->req.complete(&mEp->ep, &mReq->req);
- spin_lock(mEp->lock);
+ if (hwreq->req.complete != NULL) {
+ spin_unlock(hwep->lock);
+ hwreq->req.complete(&hwep->ep, &hwreq->req);
+ spin_lock(hwep->lock);
}
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
return 0;
}
@@ -1239,37 +1341,40 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
*/
static int ep_set_halt(struct usb_ep *ep, int value)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
int direction, retval = 0;
unsigned long flags;
- if (ep == NULL || mEp->ep.desc == NULL)
+ if (ep == NULL || hwep->ep.desc == NULL)
return -EINVAL;
- spin_lock_irqsave(mEp->lock, flags);
+ 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 && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
- !list_empty(&mEp->qh.queue)) {
- spin_unlock_irqrestore(mEp->lock, flags);
+ 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 = mEp->dir;
+ direction = hwep->dir;
do {
- retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);
+ retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
if (!value)
- mEp->wedge = 0;
+ hwep->wedge = 0;
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->dir = (mEp->dir == TX) ? RX : TX;
+ if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
+ hwep->dir = (hwep->dir == TX) ? RX : TX;
- } while (mEp->dir != direction);
+ } while (hwep->dir != direction);
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
return retval;
}
@@ -1280,15 +1385,15 @@ static int ep_set_halt(struct usb_ep *ep, int value)
*/
static int ep_set_wedge(struct usb_ep *ep)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
unsigned long flags;
- if (ep == NULL || mEp->ep.desc == NULL)
+ if (ep == NULL || hwep->ep.desc == NULL)
return -EINVAL;
- spin_lock_irqsave(mEp->lock, flags);
- mEp->wedge = 1;
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_lock_irqsave(hwep->lock, flags);
+ hwep->wedge = 1;
+ spin_unlock_irqrestore(hwep->lock, flags);
return usb_ep_set_halt(ep);
}
@@ -1300,19 +1405,19 @@ static int ep_set_wedge(struct usb_ep *ep)
*/
static void ep_fifo_flush(struct usb_ep *ep)
{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
unsigned long flags;
if (ep == NULL) {
- dev_err(mEp->ci->dev, "%02X: -EINVAL\n", _usb_addr(mEp));
+ dev_err(hwep->ci->dev, "%02X: -EINVAL\n", _usb_addr(hwep));
return;
}
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(hwep->lock, flags);
- hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
+ hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
}
/**
@@ -1334,13 +1439,13 @@ static const struct usb_ep_ops usb_ep_ops = {
/******************************************************************************
* GADGET block
*****************************************************************************/
-static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
+static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{
- struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
+ struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
unsigned long flags;
int gadget_ready = 0;
- if (!(ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS))
+ if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS))
return -EOPNOTSUPP;
spin_lock_irqsave(&ci->lock, flags);
@@ -1358,7 +1463,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
hw_device_state(ci, 0);
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
- CI13XXX_CONTROLLER_STOPPED_EVENT);
+ CI_HDRC_CONTROLLER_STOPPED_EVENT);
_gadget_stop_activity(&ci->gadget);
pm_runtime_put_sync(&_gadget->dev);
}
@@ -1367,9 +1472,9 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
return 0;
}
-static int ci13xxx_wakeup(struct usb_gadget *_gadget)
+static int ci_udc_wakeup(struct usb_gadget *_gadget)
{
- struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
+ struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
unsigned long flags;
int ret = 0;
@@ -1388,21 +1493,21 @@ out:
return ret;
}
-static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
{
- struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
+ struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
if (ci->transceiver)
- return usb_phy_set_power(ci->transceiver, mA);
+ return usb_phy_set_power(ci->transceiver, ma);
return -ENOTSUPP;
}
/* Change Data+ pullup status
* this func is used by usb_gadget_connect/disconnet
*/
-static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on)
+static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
{
- struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
+ struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
if (is_on)
hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
@@ -1412,9 +1517,9 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on)
return 0;
}
-static int ci13xxx_start(struct usb_gadget *gadget,
+static int ci_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
-static int ci13xxx_stop(struct usb_gadget *gadget,
+static int ci_udc_stop(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
/**
* Device operations part of the API to the USB controller hardware,
@@ -1422,46 +1527,46 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
* Check "usb_gadget.h" for details
*/
static const struct usb_gadget_ops usb_gadget_ops = {
- .vbus_session = ci13xxx_vbus_session,
- .wakeup = ci13xxx_wakeup,
- .pullup = ci13xxx_pullup,
- .vbus_draw = ci13xxx_vbus_draw,
- .udc_start = ci13xxx_start,
- .udc_stop = ci13xxx_stop,
+ .vbus_session = ci_udc_vbus_session,
+ .wakeup = ci_udc_wakeup,
+ .pullup = ci_udc_pullup,
+ .vbus_draw = ci_udc_vbus_draw,
+ .udc_start = ci_udc_start,
+ .udc_stop = ci_udc_stop,
};
-static int init_eps(struct ci13xxx *ci)
+static int init_eps(struct ci_hdrc *ci)
{
int retval = 0, i, j;
for (i = 0; i < ci->hw_ep_max/2; i++)
for (j = RX; j <= TX; j++) {
int k = i + j * ci->hw_ep_max/2;
- struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[k];
+ struct ci_hw_ep *hwep = &ci->ci_hw_ep[k];
- scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+ scnprintf(hwep->name, sizeof(hwep->name), "ep%i%s", i,
(j == TX) ? "in" : "out");
- mEp->ci = ci;
- mEp->lock = &ci->lock;
- mEp->td_pool = ci->td_pool;
+ hwep->ci = ci;
+ hwep->lock = &ci->lock;
+ hwep->td_pool = ci->td_pool;
- mEp->ep.name = mEp->name;
- mEp->ep.ops = &usb_ep_ops;
+ hwep->ep.name = hwep->name;
+ hwep->ep.ops = &usb_ep_ops;
/*
* for ep0: maxP defined in desc, for other
* eps, maxP is set by epautoconfig() called
* by gadget layer
*/
- mEp->ep.maxpacket = (unsigned short)~0;
+ hwep->ep.maxpacket = (unsigned short)~0;
- INIT_LIST_HEAD(&mEp->qh.queue);
- mEp->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL,
- &mEp->qh.dma);
- if (mEp->qh.ptr == NULL)
+ INIT_LIST_HEAD(&hwep->qh.queue);
+ hwep->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL,
+ &hwep->qh.dma);
+ if (hwep->qh.ptr == NULL)
retval = -ENOMEM;
else
- memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+ memset(hwep->qh.ptr, 0, sizeof(*hwep->qh.ptr));
/*
* set up shorthands for ep0 out and in endpoints,
@@ -1469,42 +1574,42 @@ static int init_eps(struct ci13xxx *ci)
*/
if (i == 0) {
if (j == RX)
- ci->ep0out = mEp;
+ ci->ep0out = hwep;
else
- ci->ep0in = mEp;
+ ci->ep0in = hwep;
- mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+ hwep->ep.maxpacket = CTRL_PAYLOAD_MAX;
continue;
}
- list_add_tail(&mEp->ep.ep_list, &ci->gadget.ep_list);
+ list_add_tail(&hwep->ep.ep_list, &ci->gadget.ep_list);
}
return retval;
}
-static void destroy_eps(struct ci13xxx *ci)
+static void destroy_eps(struct ci_hdrc *ci)
{
int i;
for (i = 0; i < ci->hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
+ struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
- dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+ dma_pool_free(ci->qh_pool, hwep->qh.ptr, hwep->qh.dma);
}
}
/**
- * ci13xxx_start: register a gadget driver
+ * ci_udc_start: register a gadget driver
* @gadget: our gadget
* @driver: the driver being registered
*
* Interrupts are enabled here.
*/
-static int ci13xxx_start(struct usb_gadget *gadget,
+static int ci_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
- struct ci13xxx *ci = container_of(gadget, struct ci13xxx, gadget);
+ struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
unsigned long flags;
int retval = -ENOMEM;
@@ -1525,9 +1630,9 @@ static int ci13xxx_start(struct usb_gadget *gadget,
ci->driver = driver;
pm_runtime_get_sync(&ci->gadget.dev);
- if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
+ if (ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) {
if (ci->vbus_active) {
- if (ci->platdata->flags & CI13XXX_REGS_SHARED)
+ if (ci->platdata->flags & CI_HDRC_REGS_SHARED)
hw_device_reset(ci, USBMODE_CM_DC);
} else {
pm_runtime_put_sync(&ci->gadget.dev);
@@ -1545,22 +1650,22 @@ static int ci13xxx_start(struct usb_gadget *gadget,
}
/**
- * ci13xxx_stop: unregister a gadget driver
+ * ci_udc_stop: unregister a gadget driver
*/
-static int ci13xxx_stop(struct usb_gadget *gadget,
+static int ci_udc_stop(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
- struct ci13xxx *ci = container_of(gadget, struct ci13xxx, gadget);
+ struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
unsigned long flags;
spin_lock_irqsave(&ci->lock, flags);
- if (!(ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) ||
+ if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) ||
ci->vbus_active) {
hw_device_state(ci, 0);
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
- CI13XXX_CONTROLLER_STOPPED_EVENT);
+ CI_HDRC_CONTROLLER_STOPPED_EVENT);
ci->driver = NULL;
spin_unlock_irqrestore(&ci->lock, flags);
_gadget_stop_activity(&ci->gadget);
@@ -1582,7 +1687,7 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
* This function returns IRQ_HANDLED if the IRQ has been handled
* It locks access to registers
*/
-static irqreturn_t udc_irq(struct ci13xxx *ci)
+static irqreturn_t udc_irq(struct ci_hdrc *ci)
{
irqreturn_t retval;
u32 intr;
@@ -1592,7 +1697,7 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
spin_lock(&ci->lock);
- if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
+ if (ci->platdata->flags & CI_HDRC_REGS_SHARED) {
if (hw_read(ci, OP_USBMODE, USBMODE_CM) !=
USBMODE_CM_DC) {
spin_unlock(&ci->lock);
@@ -1642,7 +1747,7 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
* udc_start: initialize gadget role
* @ci: chipidea controller
*/
-static int udc_start(struct ci13xxx *ci)
+static int udc_start(struct ci_hdrc *ci)
{
struct device *dev = ci->dev;
int retval = 0;
@@ -1658,15 +1763,15 @@ static int udc_start(struct ci13xxx *ci)
INIT_LIST_HEAD(&ci->gadget.ep_list);
/* alloc resources */
- ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
- sizeof(struct ci13xxx_qh),
- 64, CI13XXX_PAGE_SIZE);
+ ci->qh_pool = dma_pool_create("ci_hw_qh", dev,
+ sizeof(struct ci_hw_qh),
+ 64, CI_HDRC_PAGE_SIZE);
if (ci->qh_pool == NULL)
return -ENOMEM;
- ci->td_pool = dma_pool_create("ci13xxx_td", dev,
- sizeof(struct ci13xxx_td),
- 64, CI13XXX_PAGE_SIZE);
+ ci->td_pool = dma_pool_create("ci_hw_td", dev,
+ sizeof(struct ci_hw_td),
+ 64, CI_HDRC_PAGE_SIZE);
if (ci->td_pool == NULL) {
retval = -ENOMEM;
goto free_qh_pool;
@@ -1684,14 +1789,14 @@ static int udc_start(struct ci13xxx *ci)
ci->transceiver = NULL;
}
- if (ci->platdata->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+ if (ci->platdata->flags & CI_HDRC_REQUIRE_TRANSCEIVER) {
if (ci->transceiver == NULL) {
retval = -ENODEV;
goto destroy_eps;
}
}
- if (!(ci->platdata->flags & CI13XXX_REGS_SHARED)) {
+ if (!(ci->platdata->flags & CI_HDRC_REGS_SHARED)) {
retval = hw_device_reset(ci, USBMODE_CM_DC);
if (retval)
goto put_transceiver;
@@ -1738,7 +1843,7 @@ free_qh_pool:
*
* No interrupts active, the IRQ has been released
*/
-static void udc_stop(struct ci13xxx *ci)
+static void udc_stop(struct ci_hdrc *ci)
{
if (ci == NULL)
return;
@@ -1765,7 +1870,7 @@ static void udc_stop(struct ci13xxx *ci)
*
* This function enables the gadget role, if the device is "device capable".
*/
-int ci_hdrc_gadget_init(struct ci13xxx *ci)
+int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index d12e8b5..455ac21 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -20,7 +20,7 @@
#define TX 1 /* similar to USB_DIR_IN but can be used as an index */
/* DMA layout of transfer descriptors */
-struct ci13xxx_td {
+struct ci_hw_td {
/* 0 */
u32 next;
#define TD_TERMINATE BIT(0)
@@ -43,24 +43,31 @@ struct ci13xxx_td {
} __attribute__ ((packed, aligned(4)));
/* DMA layout of queue heads */
-struct ci13xxx_qh {
+struct ci_hw_qh {
/* 0 */
u32 cap;
#define QH_IOS BIT(15)
#define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30)
+#define QH_ISO_MULT(x) ((x >> 11) & 0x03)
/* 1 */
u32 curr;
/* 2 - 8 */
- struct ci13xxx_td td;
+ struct ci_hw_td td;
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
} __attribute__ ((packed, aligned(4)));
+struct td_node {
+ struct list_head td;
+ dma_addr_t dma;
+ struct ci_hw_td *ptr;
+};
+
/**
- * struct ci13xxx_req - usb request representation
+ * struct ci_hw_req - usb request representation
* @req: request structure for gadget drivers
* @queue: link to QH list
* @ptr: transfer descriptor for this request
@@ -68,22 +75,19 @@ struct ci13xxx_qh {
* @zptr: transfer descriptor for the zero packet
* @zdma: dma address of the zero packet's transfer descriptor
*/
-struct ci13xxx_req {
+struct ci_hw_req {
struct usb_request req;
struct list_head queue;
- struct ci13xxx_td *ptr;
- dma_addr_t dma;
- struct ci13xxx_td *zptr;
- dma_addr_t zdma;
+ struct list_head tds;
};
#ifdef CONFIG_USB_CHIPIDEA_UDC
-int ci_hdrc_gadget_init(struct ci13xxx *ci);
+int ci_hdrc_gadget_init(struct ci_hdrc *ci);
#else
-static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
+static inline int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
return -ENXIO;
}
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 714a6bd..ac5a461 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -16,7 +16,7 @@
#include <linux/io.h>
#include <linux/delay.h>
-#include "ci13xxx_imx.h"
+#include "ci_hdrc_imx.h"
#define USB_DEV_MAX 4
@@ -175,6 +175,7 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
},
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
static int usbmisc_imx_probe(struct platform_device *pdev)
{
@@ -243,17 +244,7 @@ static struct platform_driver usbmisc_imx_driver = {
},
};
-int usbmisc_imx_drv_init(void)
-{
- return platform_driver_register(&usbmisc_imx_driver);
-}
-subsys_initcall(usbmisc_imx_drv_init);
-
-void usbmisc_imx_drv_exit(void)
-{
- platform_driver_unregister(&usbmisc_imx_driver);
-}
-module_exit(usbmisc_imx_drv_exit);
+module_platform_driver(usbmisc_imx_driver);
MODULE_ALIAS("platform:usbmisc-imx");
MODULE_LICENSE("GPL v2");