aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/chipidea
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c24
-rw-r--r--drivers/usb/chipidea/core.c11
-rw-r--r--drivers/usb/chipidea/otg.h5
-rw-r--r--drivers/usb/chipidea/otg_fsm.c69
-rw-r--r--drivers/usb/chipidea/udc.c22
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c10
6 files changed, 81 insertions, 60 deletions
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index 2d51d852b47..d72b9d2de2c 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -47,6 +47,7 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
.name = "ci_hdrc_msm",
+ .capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REGS_SHARED |
CI_HDRC_REQUIRE_TRANSCEIVER |
CI_HDRC_DISABLE_STREAMING,
@@ -57,9 +58,21 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
static int ci_hdrc_msm_probe(struct platform_device *pdev)
{
struct platform_device *plat_ci;
+ struct usb_phy *phy;
dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n");
+ /*
+ * OTG(PHY) driver takes care of PHY initialization, clock management,
+ * powering up VBUS, mapping of registers address space and power
+ * management.
+ */
+ phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ ci_hdrc_msm_platdata.phy = phy;
+
plat_ci = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
&ci_hdrc_msm_platdata);
@@ -86,10 +99,19 @@ static int ci_hdrc_msm_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id msm_ci_dt_match[] = {
+ { .compatible = "qcom,ci-hdrc", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, msm_ci_dt_match);
+
static struct platform_driver ci_hdrc_msm_driver = {
.probe = ci_hdrc_msm_probe,
.remove = ci_hdrc_msm_remove,
- .driver = { .name = "msm_hsusb", },
+ .driver = {
+ .name = "msm_hsusb",
+ .of_match_table = msm_ci_dt_match,
+ },
};
module_platform_driver(ci_hdrc_msm_driver);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 128b92ba58a..619d13e2999 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -23,7 +23,7 @@
* - BUS: bus glue code, bus abstraction layer
*
* Compile Options
- * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
+ * - CONFIG_USB_CHIPIDEA_DEBUG: enable debug facilities
* - STALL_IN: non-empty bulk-in pipes cannot be halted
* if defined mass storage compliance succeeds but with warnings
* => case 4: Hi > Dn
@@ -42,9 +42,6 @@
* - Not Supported: 15 & 16 (ISO)
*
* TODO List
- * - Interrupt Traffic
- * - GET_STATUS(device) - always reports 0
- * - Gadget API (majority of optional features)
* - Suspend & Remote Wakeup
*/
#include <linux/delay.h>
@@ -428,8 +425,7 @@ static irqreturn_t ci_irq(int irq, void *data)
ci->id_event = true;
/* Clear ID change irq status */
hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
return IRQ_HANDLED;
}
@@ -441,8 +437,7 @@ static irqreturn_t ci_irq(int irq, void *data)
ci->b_sess_valid_event = true;
/* Clear BSV irq */
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
return IRQ_HANDLED;
}
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
index 73492675411..9ecb598e48f 100644
--- a/drivers/usb/chipidea/otg.h
+++ b/drivers/usb/chipidea/otg.h
@@ -17,5 +17,10 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci);
void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
enum ci_role ci_otg_role(struct ci_hdrc *ci);
void ci_handle_vbus_change(struct ci_hdrc *ci);
+static inline void ci_otg_queue_work(struct ci_hdrc *ci)
+{
+ disable_irq_nosync(ci->irq);
+ queue_work(ci->wq, &ci->work);
+}
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 8d4c33dea12..caaabc58021 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -84,8 +84,7 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
ci->fsm.a_bus_req = 1;
}
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
mutex_unlock(&ci->fsm.lock);
return count;
@@ -125,8 +124,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
ci->fsm.a_bus_req = 0;
}
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
mutex_unlock(&ci->fsm.lock);
return count;
@@ -165,8 +163,7 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
else if (buf[0] == '1')
ci->fsm.b_bus_req = 1;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
mutex_unlock(&ci->fsm.lock);
return count;
@@ -186,8 +183,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
if (buf[0] == '1')
ci->fsm.a_clr_err = 1;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
mutex_unlock(&ci->fsm.lock);
return count;
@@ -297,8 +293,7 @@ static void set_tmout_and_fsm(void *ptr, unsigned long indicator)
set_tmout(ci, indicator);
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator)
@@ -312,8 +307,7 @@ static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator)
hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS);
/* Enable data pulse irq */
hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE);
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
static void b_ase0_brst_tmout_func(void *ptr, unsigned long indicator)
@@ -324,8 +318,7 @@ static void b_ase0_brst_tmout_func(void *ptr, unsigned long indicator)
if (!hw_read_otgsc(ci, OTGSC_BSV))
ci->fsm.b_sess_vld = 0;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator)
@@ -335,10 +328,8 @@ static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator)
set_tmout(ci, indicator);
/* only vbus fall below B_sess_vld in b_idle state */
- if (ci->transceiver->state == OTG_STATE_B_IDLE) {
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
- }
+ if (ci->transceiver->state == OTG_STATE_B_IDLE)
+ ci_otg_queue_work(ci);
}
static void b_sess_vld_tmout_func(void *ptr, unsigned long indicator)
@@ -349,8 +340,7 @@ static void b_sess_vld_tmout_func(void *ptr, unsigned long indicator)
if (!(hw_read_otgsc(ci, OTGSC_BSV))) {
ci->fsm.b_sess_vld = 0;
ci_otg_add_timer(ci, B_SSEND_SRP);
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
}
@@ -365,8 +355,7 @@ static void b_data_pulse_end(void *ptr, unsigned long indicator)
hw_write_otgsc(ci, OTGSC_HABA, 0);
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
/* Initialize timers */
@@ -607,10 +596,8 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
* a_idle to a_wait_vrise when power up
*/
if ((ci->fsm.id) || (ci->id_event) ||
- (ci->fsm.power_up)) {
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
- }
+ (ci->fsm.power_up))
+ ci_otg_queue_work(ci);
if (ci->id_event)
ci->id_event = false;
} else if (ci->transceiver->state == OTG_STATE_B_IDLE) {
@@ -620,8 +607,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
* Further transite to b_periphearl state
* when register gadget driver with vbus on
*/
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
}
}
@@ -646,22 +632,19 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
if (port_conn) {
fsm->b_conn = 1;
fsm->a_bus_req = 1;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
break;
case OTG_STATE_B_IDLE:
if (otg_bsess_vld && (intr_sts & USBi_PCI) && port_conn) {
fsm->b_sess_vld = 1;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
break;
case OTG_STATE_B_PERIPHERAL:
if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) {
fsm->a_bus_suspend = 1;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
} else if (intr_sts & USBi_PCI) {
if (fsm->a_bus_suspend == 1)
fsm->a_bus_suspend = 0;
@@ -671,8 +654,7 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
if ((intr_sts & USBi_PCI) && !port_conn) {
fsm->a_conn = 0;
fsm->b_bus_req = 0;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
ci_otg_add_timer(ci, B_SESS_VLD);
}
break;
@@ -706,22 +688,19 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
/* A device to be peripheral mode */
ci->gadget.is_a_peripheral = 1;
}
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
break;
case OTG_STATE_A_HOST:
if ((intr_sts & USBi_PCI) && !port_conn) {
fsm->b_conn = 0;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
break;
case OTG_STATE_B_WAIT_ACON:
if ((intr_sts & USBi_PCI) && port_conn) {
fsm->a_conn = 1;
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
break;
default:
@@ -782,8 +761,7 @@ irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci)
fsm->b_conn = 0;
}
}
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
return IRQ_HANDLED;
}
@@ -794,8 +772,7 @@ irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci)
void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci)
{
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ ci_otg_queue_work(ci);
}
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 150592f10b3..b8125aa64ad 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -709,6 +709,8 @@ __acquires(ci->lock)
if (ci->status == NULL)
retval = -ENOMEM;
+ usb_gadget_set_state(&ci->gadget, USB_STATE_DEFAULT);
+
done:
spin_lock(&ci->lock);
@@ -823,7 +825,6 @@ __acquires(hwep->lock)
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
/* Assume that device is bus powered for now. */
*(u16 *)req->buf = ci->remote_wakeup << 1;
- retval = 0;
} else if ((setup->bRequestType & USB_RECIP_MASK) \
== USB_RECIP_ENDPOINT) {
dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
@@ -865,6 +866,8 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
if (ci->setaddr) {
hw_usb_set_address(ci, ci->address);
ci->setaddr = false;
+ if (ci->address)
+ usb_gadget_set_state(&ci->gadget, USB_STATE_ADDRESS);
}
spin_lock_irqsave(&ci->lock, flags);
@@ -1166,8 +1169,8 @@ static int ep_enable(struct usb_ep *ep,
if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
cap |= QH_IOS;
- if (hwep->num)
- cap |= QH_ZLT;
+
+ cap |= QH_ZLT;
cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
/*
* For ISO-TX, we set mult at QH as the largest value, and use
@@ -1318,6 +1321,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *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;
+ struct td_node *node, *tmpnode;
if (ep == NULL || req == NULL || hwreq->req.status != -EALREADY ||
hwep->ep.desc == NULL || list_empty(&hwreq->queue) ||
@@ -1328,6 +1332,12 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
+ list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
+ dma_pool_free(hwep->td_pool, node->ptr, node->dma);
+ list_del(&node->td);
+ kfree(node);
+ }
+
/* pop request */
list_del_init(&hwreq->queue);
@@ -1467,7 +1477,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(ci, USBMODE_CM_DC);
hw_device_state(ci, ci->ep0out->qh.dma);
- dev_dbg(ci->dev, "Connected to host\n");
+ usb_gadget_set_state(_gadget, USB_STATE_POWERED);
} else {
if (ci->driver)
ci->driver->disconnect(&ci->gadget);
@@ -1477,7 +1487,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
CI_HDRC_CONTROLLER_STOPPED_EVENT);
_gadget_stop_activity(&ci->gadget);
pm_runtime_put_sync(&_gadget->dev);
- dev_dbg(ci->dev, "Disconnected from host\n");
+ usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
}
}
@@ -1750,6 +1760,8 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
ci->suspended = 1;
spin_unlock(&ci->lock);
ci->driver->suspend(&ci->gadget);
+ usb_gadget_set_state(&ci->gadget,
+ USB_STATE_SUSPENDED);
spin_lock(&ci->lock);
}
}
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 419b8959d15..85293b8b1df 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -46,11 +46,14 @@
#define MX27_OTG_PM_BIT BIT(24)
#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
+#define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c
#define MX53_USB_UH2_CTRL_OFFSET 0x14
#define MX53_USB_UH3_CTRL_OFFSET 0x18
#define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
#define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
#define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
+#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
+#define MX53_USB_PLL_DIV_24_MHZ 0x01
#define MX6_BM_OVER_CUR_DIS BIT(7)
@@ -164,6 +167,13 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
if (data->index > 3)
return -EINVAL;
+ /* Select a 24 MHz reference clock for the PHY */
+ reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET;
+ val = readl(reg);
+ val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
+ val |= MX53_USB_PLL_DIV_24_MHZ;
+ writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
+
if (data->disable_oc) {
spin_lock_irqsave(&usbmisc->lock, flags);
switch (data->index) {