[Meego-kernel] [PATCH 2/3] usb: penwell_otg: add support for MHL-USB coexistence
Wu, Hao
hao.wu at intel.com
Mon Dec 6 04:59:04 PST 2010
>From 1b24742dc9c1bc09a54f6de2fbc2b1c79b5fcae0 Mon Sep 17 00:00:00 2001
From: Hao Wu <hao.wu at intel.com>
Date: Sun, 28 Nov 2010 15:08:02 +0800
Subject: [PATCH] usb: penwell_otg: add support for MHL-USB coexistence
Add MHL support in penwell_otg transceiver driver including
pm related support.
Signed-off-by: Hao Wu <hao.wu at intel.com>
---
drivers/usb/otg/penwell_otg.c | 164 ++++++++++++++++++++++++++++++++++-----
include/linux/usb/penwell_otg.h | 2 +-
2 files changed, 145 insertions(+), 21 deletions(-)
diff --git a/drivers/usb/otg/penwell_otg.c b/drivers/usb/otg/penwell_otg.c
index 724a516..d25959a 100644
--- a/drivers/usb/otg/penwell_otg.c
+++ b/drivers/usb/otg/penwell_otg.c
@@ -63,6 +63,9 @@ static int penwell_otg_set_peripheral(struct otg_transceiver *otg,
struct usb_gadget *gadget);
static int penwell_otg_start_srp(struct otg_transceiver *otg);
static int penwell_otg_msic_write(u16 addr, u8 data);
+static void penwell_otg_intr(int on);
+static void penwell_otg_add_timer(enum penwell_otg_timer_type timers);
+static void update_hsm(void);
static const char *state_string(enum usb_otg_state state)
{
@@ -91,6 +94,8 @@ static const char *state_string(enum usb_otg_state state)
return "b_wait_acon";
case OTG_STATE_B_HOST:
return "b_host";
+ case OTG_STATE_MHL:
+ return "mhl";
default:
return "UNDEFINED";
}
@@ -540,6 +545,111 @@ static int penwell_otg_start_srp(struct otg_transceiver *otg)
return 0;
}
+/* Enter MHL mode */
+static int penwell_otg_enter_mhl_mode(struct otg_transceiver *otg)
+{
+ struct penwell_otg *pnw = the_transceiver;
+
+ dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+ pm_runtime_get_sync(pnw->dev);
+
+ mutex_lock(&pnw->iotg.otg.state_mutex);
+
+ /* stop otg interrupt */
+ penwell_otg_intr(0);
+
+ /* move to OTG_MHL state */
+ pnw->iotg.otg.state = OTG_STATE_MHL;
+
+ mutex_unlock(&pnw->iotg.otg.state_mutex);
+
+ pm_runtime_put_sync(pnw->dev);
+
+ dev_dbg(pnw->dev, "%s <---\n", __func__);
+ return 0;
+}
+
+/* called with otg.state_mutex held */
+static int _penwell_otg_enter_mhl_mode(struct otg_transceiver *otg)
+{
+ struct penwell_otg *pnw = the_transceiver;
+
+ dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+ /* stop otg interrupt */
+ penwell_otg_intr(0);
+
+ /* move to OTG_MHL state */
+ pnw->iotg.otg.state = OTG_STATE_MHL;
+
+ dev_dbg(pnw->dev, "%s <---\n", __func__);
+ return 0;
+}
+
+/* Exit MHL mode */
+static int penwell_otg_exit_mhl_mode(struct otg_transceiver *otg)
+{
+ struct penwell_otg *pnw = the_transceiver;
+
+ dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+ mutex_lock(&pnw->iotg.otg.state_mutex);
+
+ if (pnw->iotg.otg.state != OTG_STATE_MHL)
+ return -EINVAL;
+
+ /* enable otg interrupt */
+ penwell_otg_intr(1);
+
+ pnw->iotg.hsm.power_up = 0;
+ pnw->iotg.hsm.adp_change = 0;
+ pnw->iotg.hsm.a_srp_det = 0;
+
+ if (pnw->iotg.otg.set_vbus)
+ pnw->iotg.otg.set_vbus(&pnw->iotg.otg, true);
+
+ penwell_otg_add_timer(TA_WAIT_VRISE_TMR);
+ pnw->iotg.otg.state = OTG_STATE_A_WAIT_VRISE;
+
+ update_hsm();
+ penwell_update_transceiver();
+
+ mutex_unlock(&pnw->iotg.otg.state_mutex);
+ dev_dbg(pnw->dev, "%s <---\n", __func__);
+ return 0;
+}
+
+/* called with otg.state_mutex held */
+static int _penwell_otg_exit_mhl_mode(struct otg_transceiver *otg)
+{
+ struct penwell_otg *pnw = the_transceiver;
+
+ dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+ if (pnw->iotg.otg.state != OTG_STATE_MHL)
+ return -EINVAL;
+
+ /* enable otg interrupt */
+ penwell_otg_intr(1);
+
+ pnw->iotg.hsm.power_up = 0;
+ pnw->iotg.hsm.adp_change = 0;
+ pnw->iotg.hsm.a_srp_det = 0;
+
+ if (pnw->iotg.otg.set_vbus)
+ pnw->iotg.otg.set_vbus(&pnw->iotg.otg, true);
+
+ penwell_otg_add_timer(TA_WAIT_VRISE_TMR);
+ pnw->iotg.otg.state = OTG_STATE_A_WAIT_VRISE;
+
+ update_hsm();
+ penwell_update_transceiver();
+
+ dev_dbg(pnw->dev, "%s <---\n", __func__);
+ return 0;
+}
+
/* The timeout callback function to poll the host request flag */
static void penwell_otg_hnp_poll_fn(unsigned long indicator)
{
@@ -1011,6 +1121,8 @@ static void init_hsm(void)
struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
u32 val32;
+ mutex_lock(&iotg->otg.state_mutex);
+
/* read OTGSC after reset */
val32 = readl(iotg->base + CI_OTGSC);
dev_dbg(pnw->dev,
@@ -1051,6 +1163,7 @@ static void init_hsm(void)
penwell_otg_phy_low_power(1);
+ mutex_unlock(&iotg->otg.state_mutex);
}
static void update_hsm(void)
@@ -1293,6 +1406,7 @@ static void penwell_otg_work(struct work_struct *work)
"old state = %s\n", state_string(iotg->otg.state));
pm_runtime_get_sync(pnw->dev);
+ mutex_lock(&iotg->otg.state_mutex);
switch (iotg->otg.state) {
case OTG_STATE_UNDEFINED:
@@ -1744,22 +1858,14 @@ static void penwell_otg_work(struct work_struct *work)
|| hsm->power_up || hsm->adp_change)) {
/* power up / adp changes / srp detection should be
* cleared at once after handled. */
- if (hsm->power_up)
- hsm->power_up = 0;
-
- if (hsm->adp_change)
- hsm->adp_change = 0;
-
- if (hsm->a_srp_det)
- hsm->a_srp_det = 0;
-
- if (iotg->otg.set_vbus)
- iotg->otg.set_vbus(&iotg->otg, true);
-
- penwell_otg_add_timer(TA_WAIT_VRISE_TMR);
- iotg->otg.state = OTG_STATE_A_WAIT_VRISE;
-
- penwell_update_transceiver();
+ _penwell_otg_enter_mhl_mode(&iotg->otg);
+ if (otg_mhl_notify(&iotg->otg, 1)) {
+ _penwell_otg_exit_mhl_mode(&iotg->otg);
+ penwell_update_transceiver();
+ } else {
+ dev_dbg(pnw->dev, "Now in MHL mode\n");
+ break;
+ }
} else if (hsm->b_sess_end || hsm->a_sess_vld ||
!hsm->b_sess_vld) {
dev_dbg(pnw->dev,
@@ -1819,7 +1925,8 @@ static void penwell_otg_work(struct work_struct *work)
}
break;
case OTG_STATE_A_WAIT_BCON:
- if (hsm->id == ID_B || hsm->id == ID_ACA_B || hsm->a_bus_drop) {
+ if (hsm->id == ID_B || hsm->id == ID_ACA_B || hsm->a_bus_drop ||
+ hsm->a_wait_bcon_tmout) {
/* Move to A_WAIT_VFALL state, user request */
/* Delete current timer and clear flags for B-Device */
@@ -1984,7 +2091,6 @@ static void penwell_otg_work(struct work_struct *work)
penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
/* add kernel timer */
- penwell_otg_add_timer(TA_WAIT_BCON_TMR);
iotg->otg.state = OTG_STATE_A_WAIT_BCON;
} else if (!hsm->b_conn && pnw->iotg.otg.host->b_hnp_enable) {
/* Move to A_PERIPHERAL state, HNP */
@@ -2082,7 +2188,6 @@ static void penwell_otg_work(struct work_struct *work)
dev_dbg(pnw->dev,
"host driver not loaded.\n");
- penwell_otg_add_timer(TA_WAIT_BCON_TMR);
iotg->otg.state = OTG_STATE_A_WAIT_BCON;
} else if (!hsm->b_bus_suspend && hsm->a_bidl_adis_tmr) {
/* Client report suspend state end, delete timer */
@@ -2126,6 +2231,7 @@ static void penwell_otg_work(struct work_struct *work)
;
}
+ mutex_unlock(&iotg->otg.state_mutex);
pm_runtime_put_sync(pnw->dev);
dev_dbg(pnw->dev,
@@ -2559,6 +2665,8 @@ static int penwell_otg_probe(struct pci_dev *pdev,
pnw->iotg.otg.set_power = penwell_otg_set_power;
pnw->iotg.otg.set_vbus = penwell_otg_set_vbus;
pnw->iotg.otg.start_srp = penwell_otg_start_srp;
+ pnw->iotg.otg.enter_mhl_mode = penwell_otg_enter_mhl_mode;
+ pnw->iotg.otg.exit_mhl_mode = penwell_otg_exit_mhl_mode;
pnw->iotg.set_adp_probe = NULL;
pnw->iotg.set_adp_sense = NULL;
pnw->iotg.otg.state = OTG_STATE_UNDEFINED;
@@ -2571,6 +2679,9 @@ static int penwell_otg_probe(struct pci_dev *pdev,
pnw->iotg.ulpi_ops.read = penwell_otg_ulpi_read;
pnw->iotg.ulpi_ops.write = penwell_otg_ulpi_write;
+ mutex_init(&pnw->iotg.otg.state_mutex);
+ mutex_init(&pnw->iotg.otg.mhl_mutex);
+
init_timer(&pnw->hsm_timer);
init_timer(&pnw->hnp_poll_timer);
init_completion(&pnw->adp.adp_comp);
@@ -2703,6 +2814,13 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
int ret = 0;
+ mutex_lock(&iotg->otg.state_mutex);
+ if (iotg->otg.state == OTG_STATE_MHL) {
+ mutex_unlock(&iotg->otg.state_mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&iotg->otg.state_mutex);
+
/* Disbale OTG interrupts */
penwell_otg_intr(0);
@@ -2714,6 +2832,7 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
destroy_workqueue(pnw->qwork);
pnw->qwork = NULL;
+ mutex_lock(&iotg->otg.state_mutex);
/* start actions */
switch (iotg->otg.state) {
case OTG_STATE_A_WAIT_VFALL:
@@ -2822,6 +2941,7 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
dev_dbg(pnw->dev, "error state before suspend\n");
break;
}
+ mutex_unlock(&iotg->otg.state_mutex);
return ret;
}
@@ -2882,6 +3002,7 @@ static int penwell_otg_runtime_suspend(struct device *dev)
switch (pnw->iotg.otg.state) {
case OTG_STATE_A_IDLE:
case OTG_STATE_B_IDLE:
+ case OTG_STATE_MHL:
/* Transceiver handle it itself */
penwell_otg_phy_low_power(1);
pci_save_state(pdev);
@@ -2917,13 +3038,14 @@ static int penwell_otg_runtime_resume(struct device *dev)
pdev = to_pci_dev(dev);
- penwell_otg_intr(1);
penwell_otg_phy_low_power(0);
switch (pnw->iotg.otg.state) {
case OTG_STATE_A_IDLE:
case OTG_STATE_B_IDLE:
/* Transceiver handle it itself */
+ penwell_otg_intr(1);
+ case OTG_STATE_MHL:
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
ret = pci_enable_device(pdev);
@@ -2934,11 +3056,13 @@ static int penwell_otg_runtime_resume(struct device *dev)
case OTG_STATE_A_WAIT_BCON:
case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND:
+ penwell_otg_intr(1);
if (pnw->iotg.runtime_resume_host)
ret = pnw->iotg.runtime_resume_host(&pnw->iotg);
break;
case OTG_STATE_A_PERIPHERAL:
case OTG_STATE_B_PERIPHERAL:
+ penwell_otg_intr(1);
if (pnw->iotg.runtime_resume_peripheral)
ret = pnw->iotg.runtime_resume_peripheral(&pnw->iotg);
break;
diff --git a/include/linux/usb/penwell_otg.h b/include/linux/usb/penwell_otg.h
index 77776ca..f4284d0 100644
--- a/include/linux/usb/penwell_otg.h
+++ b/include/linux/usb/penwell_otg.h
@@ -229,7 +229,7 @@ enum penwell_otg_timer_type {
};
#define TA_WAIT_VRISE 100
-#define TA_WAIT_BCON 30000
+#define TA_WAIT_BCON 15000
#define TA_AIDL_BDIS 1500
#define TA_BIDL_ADIS 300
#define TA_WAIT_VFALL 950
--
1.6.0.6
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-usb-penwell_otg-add-support-for-MHL-USB-coexistenc.patch
Type: application/octet-stream
Size: 10217 bytes
Desc: 0002-usb-penwell_otg-add-support-for-MHL-USB-coexistenc.patch
URL: <http://lists.meego.com/pipermail/meego-kernel/attachments/20101206/3db26fa6/attachment-0001.obj>
More information about the MeeGo-kernel
mailing list