USB: msm_otg: Update HTC variant of msm_otg
HTC kernel version: m7stock_3.4.10-g1a25406
Change-Id: I2707390c287a6d2a9f05814aea25362347240048
diff --git a/arch/arm/mach-msm/include/mach/board-ext-htc.h b/arch/arm/mach-msm/include/mach/board-ext-htc.h
index 8d14695..defd95b 100644
--- a/arch/arm/mach-msm/include/mach/board-ext-htc.h
+++ b/arch/arm/mach-msm/include/mach/board-ext-htc.h
@@ -27,6 +27,7 @@
void msm_otg_set_vbus_state(int online);
enum usb_connect_type {
+ CONNECT_TYPE_NOTIFY = -3,
CONNECT_TYPE_CLEAR = -2,
CONNECT_TYPE_UNKNOWN = -1,
CONNECT_TYPE_NONE = 0,
diff --git a/arch/arm/mach-msm/include/mach/cable_detect.h b/arch/arm/mach-msm/include/mach/cable_detect.h
index 172692a..0217be7 100644
--- a/arch/arm/mach-msm/include/mach/cable_detect.h
+++ b/arch/arm/mach-msm/include/mach/cable_detect.h
@@ -10,12 +10,24 @@
#define DOCK_STATE_USB_HOST (1 << 4)
#define DOCK_STATE_DMB (1 << 5)
#define DOCK_STATE_AUDIO_DOCK (1 << 6)
-
+#ifdef CONFIG_USB_OTG_HOST_CHG
+#define DOCK_STATE_HOST_CHG_DOCK (1 << 7)
+#else
+#define DOCK_STATE_THREE_POGO_DOCK (1 << 7)
+#endif
#define DOCK_DET_DELAY HZ/4
-
+#ifdef CONFIG_MACH_TC2
+#define ADC_RETRY 5
+#else
#define ADC_RETRY 3
-#define ADC_DELAY HZ/8
+#endif
+#ifdef CONFIG_USB_OTG_HOST_CHG
+#define ADC_DELAY HZ/8
+#define HOST_DET_DELAY HZ/2
+#else
+#define ADC_DELAY HZ/8
+#endif
#define PM8058ADC_15BIT(adc) ((adc * 2200) / 32767)
#define CABLE_ERR(fmt, args...) \
@@ -83,6 +95,9 @@
bool dock_detect;
int dock_pin_gpio;
#endif
+ int idpin_irq;
+ int carkit_only;
+ int (*detect_three_pogo_dock)(void);
int enable_vbus_usb_switch;
};
@@ -95,4 +110,5 @@
extern int cable_get_usb_id_level(void);
extern void cable_set_uart_switch(int);
extern irqreturn_t cable_detection_vbus_irq_handler(void);
+extern int check_three_pogo_dock(void);
#endif
diff --git a/drivers/misc/cable_detect_8xxx.c b/drivers/misc/cable_detect_8xxx.c
index 2264469..f321e2b 100644
--- a/drivers/misc/cable_detect_8xxx.c
+++ b/drivers/misc/cable_detect_8xxx.c
@@ -90,6 +90,7 @@
int audio_dock_lock;
int notify_init;
+ int (*detect_three_pogo_dock)(void);
int enable_vbus_usb_switch;
} the_cable_info;
@@ -158,6 +159,7 @@
return 0;
}
+#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
static DEFINE_MUTEX(usb_host_notify_sem);
static void send_usb_host_connect_notify(int cable_in)
{
@@ -189,11 +191,15 @@
mutex_unlock(&usb_host_notify_sem);
return 0;
}
+#endif
static void check_vbus_in(struct work_struct *w)
{
int vbus_in;
int level;
+#if 0
+ int three_pogo_charging_type;
+#endif
struct cable_detect_info *pInfo = container_of(
w, struct cable_detect_info, vbus_detect_work.work);
@@ -213,7 +219,6 @@
&pInfo->cable_detect_work, ADC_DELAY);
}
#endif
-
if (pInfo->notify_init == 0 && vbus_in == 0 && vbus == 0)
send_cable_connect_notify(CONNECT_TYPE_NONE);
if (pInfo->notify_init == 0 && vbus == vbus_in)
@@ -221,6 +226,37 @@
pInfo->notify_init = 1;
+#if 0
+ if (pInfo->detect_three_pogo_dock) {
+ printk(KERN_INFO "[CABLE]cable detect_three_pogo_dock\n");
+ if (vbus_in && pInfo->accessory_type == DOCK_STATE_UNDOCKED) {
+ three_pogo_charging_type = pInfo->detect_three_pogo_dock();
+ printk(KERN_INFO "[CABLE]cable detect_three_pogo_dock return %d\n",three_pogo_charging_type);
+ if (three_pogo_charging_type > 0) {
+ switch_set_state(&dock_switch, DOCK_STATE_DESK);
+ pInfo->accessory_type = DOCK_STATE_THREE_POGO_DOCK;
+ CABLE_INFO("three pogo dock\n");
+ if (three_pogo_charging_type == 1)
+ send_cable_connect_notify(CONNECT_TYPE_USB);
+ else if (three_pogo_charging_type == 2)
+ send_cable_connect_notify(CONNECT_TYPE_AC);
+ wake_unlock(&pInfo->vbus_wlock);
+ return;
+ }
+ } else {
+ if (pInfo->accessory_type == DOCK_STATE_THREE_POGO_DOCK) {
+
+ switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
+ pInfo->accessory_type = DOCK_STATE_UNDOCKED;
+ CABLE_INFO("three pogo dock removed\n");
+ send_cable_connect_notify(CONNECT_TYPE_NONE);
+ wake_unlock(&pInfo->vbus_wlock);
+ return;
+ }
+ }
+ }
+#endif
+
if (vbus != vbus_in) {
vbus = vbus_in;
@@ -284,7 +320,11 @@
if (adc > -100 && adc < 100)
type = second_detect(pInfo);
else {
+#ifdef CONFIG_MACH_DUMMY
+ if (adc > 120 && adc < 220)
+#else
if (adc > 150 && adc < 220)
+#endif
type = DOCK_STATE_CAR;
else if (adc > 370 && adc < 440)
type = DOCK_STATE_USB_HEADSET;
@@ -318,7 +358,6 @@
w, struct cable_detect_info, cable_detect_work.work);
int value;
int accessory_type;
-
if (pInfo == NULL)
return;
if(pInfo->audio_dock_lock == 1) {
@@ -338,7 +377,6 @@
}
} else
accessory_type = DOCK_STATE_UNDOCKED;
-
#ifdef CONFIG_FB_MSM_HDMI_MHL_SII9234
if (pInfo->mhl_reset_gpio != 0)
gpio_set_value_cansleep(pInfo->mhl_reset_gpio, 1);
@@ -392,12 +430,14 @@
sii9234_mhl_device_wakeup();
break;
#endif
+#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
case DOCK_STATE_USB_HOST:
CABLE_INFO("USB Host inserted\n");
send_usb_host_connect_notify(1);
pInfo->accessory_type = DOCK_STATE_USB_HOST;
switch_set_state(&dock_switch, DOCK_STATE_USB_HOST);
break;
+#endif
case DOCK_STATE_DMB:
CABLE_INFO("DMB inserted\n");
send_cable_connect_notify(CONNECT_TYPE_CLEAR);
@@ -422,6 +462,14 @@
#endif
#endif
break;
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ case DOCK_STATE_HOST_CHG_DOCK:
+ CABLE_INFO("USB Host charger inserted\n");
+ send_usb_host_connect_notify(1);
+ pInfo->accessory_type = DOCK_STATE_HOST_CHG_DOCK;
+ switch_set_state(&dock_switch, DOCK_STATE_USB_HOST);
+ break;
+#endif
case DOCK_STATE_UNDEFINED:
case DOCK_STATE_UNDOCKED:
switch (pInfo->accessory_type) {
@@ -451,12 +499,14 @@
sii9234_disableIRQ();
break;
#endif
+#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
case DOCK_STATE_USB_HOST:
CABLE_INFO("USB host cable removed\n");
pInfo->accessory_type = DOCK_STATE_UNDOCKED;
send_usb_host_connect_notify(0);
switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
break;
+#endif
case DOCK_STATE_DMB:
CABLE_INFO("DMB removed\n");
switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
@@ -470,6 +520,13 @@
#endif
pInfo->accessory_type = DOCK_STATE_UNDOCKED;
break;
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ case DOCK_STATE_HOST_CHG_DOCK:
+ CABLE_INFO("USB host charger removed\n");
+ send_usb_host_connect_notify(0);
+ switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
+ break;
+#endif
}
default :
break;
@@ -504,6 +561,17 @@
return the_cable_info.accessory_type;
}
+int check_three_pogo_dock(void)
+{
+ int three_pogo_charging_type;
+ if (the_cable_info.detect_three_pogo_dock) {
+ three_pogo_charging_type = the_cable_info.detect_three_pogo_dock();
+ printk(KERN_INFO "[CABLE]cable detect_three_pogo_dock return %d\n",three_pogo_charging_type);
+ return three_pogo_charging_type;
+ }
+ return 0;
+}
+
static int cable_detect_get_adc(void)
{
struct cable_detect_info *pInfo = &the_cable_info;
@@ -541,9 +609,17 @@
type = DOCK_STATE_UNDEFINED;
#endif
else if(adc_value >= 1021 && adc_value <= 1224)
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ type = DOCK_STATE_HOST_CHG_DOCK;
+#else
type = DOCK_STATE_AUDIO_DOCK;
+#endif
else
+#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
type = DOCK_STATE_USB_HOST;
+#else
+ type = DOCK_STATE_UNDEFINED;
+#endif
if (pInfo->config_usb_id_gpios)
pInfo->config_usb_id_gpios(0);
@@ -586,8 +662,13 @@
CABLE_INFO("usb: id interrupt\n");
pInfo->cable_redetect = 0;
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ queue_delayed_work(pInfo->cable_detect_wq,
+ &pInfo->cable_detect_work, HOST_DET_DELAY);
+#else
queue_delayed_work(pInfo->cable_detect_wq,
&pInfo->cable_detect_work, ADC_DELAY);
+#endif
wake_lock_timeout(&pInfo->cable_detect_wlock, HZ*2);
return IRQ_HANDLED;
}
@@ -879,6 +960,7 @@
pInfo->mhl_version_ctrl_flag = pdata->mhl_version_ctrl_flag;
pInfo->mhl_1v2_power = pdata->mhl_1v2_power;
pInfo->get_adc_cb = pdata->get_adc_cb;
+ pInfo->detect_three_pogo_dock = pdata->detect_three_pogo_dock;
pInfo->enable_vbus_usb_switch = pdata->enable_vbus_usb_switch;
#endif
@@ -991,7 +1073,7 @@
struct cable_detect_info*pInfo = &the_cable_info;
CABLE_INFO("%s: cable_type = %d\n", __func__, cable_type);
-
+#ifndef CONFIG_USB_OTG_HOST_CHG
if(pInfo->audio_dock_lock == 0 && (cable_type == CONNECT_TYPE_USB || cable_type == CONNECT_TYPE_AC || cable_type == CONNECT_TYPE_MHL_AC))
if(pInfo->accessory_type == DOCK_STATE_AUDIO_DOCK) {
@@ -1008,7 +1090,7 @@
}
#endif
}
-
+#endif
if (cable_type > CONNECT_TYPE_NONE ||
cable_type == CONNECT_TYPE_UNKNOWN) {
if (pInfo->ad_en_gpio) {
diff --git a/drivers/usb/otg/msm_otg_htc.c b/drivers/usb/otg/msm_otg_htc.c
index 6fc9595..29977bb 100644
--- a/drivers/usb/otg/msm_otg_htc.c
+++ b/drivers/usb/otg/msm_otg_htc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,9 @@
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/power_supply.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
#include <mach/clk.h>
#include <mach/msm_xo.h>
@@ -53,23 +56,38 @@
#define MSM_USB_BASE (motg->regs)
#define DRIVER_NAME "msm_otg"
+extern int htc_battery_set_max_input_current(int target_ma);
static int htc_otg_vbus;
-static int USB_disabled;
+int USB_disabled;
static struct msm_otg *the_msm_otg;
+static int re_enable_host;
+static int stop_usb_host;
+
enum {
NOT_ON_AUTOBOT,
DOCK_ON_AUTOBOT,
HTC_MODE_RUNNING
};
+
+enum {
+ DEFAULT_STATE,
+ TRY_STOP_HOST_STATE,
+ STOP_HOST_STATE,
+ TRY_ENABLE_HOST_STATE
+};
+
+static DEFINE_MUTEX(smwork_sem);
static DEFINE_MUTEX(notify_sem);
static void send_usb_connect_notify(struct work_struct *w)
{
static struct t_usb_status_notifier *notifier;
struct msm_otg *motg = container_of(w, struct msm_otg, notifier_work);
+ struct usb_otg *otg;
if (!motg)
return;
+ otg = motg->phy.otg;
motg->connect_type_ready = 1;
USBH_INFO("send connect type %d\n", motg->connect_type);
@@ -78,13 +96,21 @@
if (notifier->func != NULL) {
/* Notify other drivers about connect type. */
/* use slow charging for unknown type*/
+#if 0
if (motg->connect_type == CONNECT_TYPE_UNKNOWN)
notifier->func(CONNECT_TYPE_USB);
else
+#endif
notifier->func(motg->connect_type);
}
}
mutex_unlock(¬ify_sem);
+ if ((board_mfg_mode() == 5 || USB_disabled )&& motg->connect_type == CONNECT_TYPE_USB) {
+ pm_runtime_put_noidle(otg->phy->dev);
+ pm_runtime_suspend(otg->phy->dev);
+ }
+ if (motg->chg_type == USB_CDP_CHARGER)
+ htc_battery_set_max_input_current(900);
}
int htc_usb_register_notifier(struct t_usb_status_notifier *notifier)
@@ -171,7 +197,6 @@
static struct regulator *hsusb_3p3;
static struct regulator *hsusb_1p8;
static struct regulator *hsusb_vddcx;
-/*static struct regulator *vbus_otg;*/
static struct regulator *mhl_usb_hs_switch;
static struct power_supply *psy;
@@ -934,7 +959,7 @@
struct usb_otg *otg = motg->phy.otg;
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
- bool host_bus_suspend, device_bus_suspend, dcp;
+ bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
u32 portsc;
@@ -950,6 +975,15 @@
test_bit(A_BUS_SUSPEND, &motg->inputs) &&
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
+ prop_charger = motg->chg_type == USB_PROPRIETARY_CHARGER;
+
+
+ if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
+ !dcp && !prop_charger) {
+ enable_irq(motg->irq);
+ return -EBUSY;
+ }
+
/*
* Chipidea 45-nm PHY suspend sequence:
*
@@ -1011,11 +1045,12 @@
* enable asynchronous interrupt to detect charger disconnection when
* PMIC notifications are unavailable.
*/
+
if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
USBH_INFO("%s:enable the ASYNC_INTR\n", __func__);
cmd_val = readl_relaxed(USB_USBCMD);
if (host_bus_suspend || device_bus_suspend ||
- (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
+ (motg->pdata->otg_control == OTG_PHY_CONTROL))
cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
else
cmd_val |= ULPI_STP_CTRL;
@@ -1065,7 +1100,9 @@
motg->lpm_flags |= PHY_PWR_COLLAPSED;
}
- if (motg->lpm_flags & PHY_RETENTIONED) {
+
+ if ((motg->lpm_flags & PHY_RETENTIONED) ||
+ (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY && !host_bus_suspend && !device_bus_suspend && !dcp)) {
msm_hsusb_config_vddcx(0);
msm_hsusb_mhl_switch_enable(motg, 0);
}
@@ -1086,25 +1123,23 @@
return 0;
}
-/*HTC_WIFI_START*/
int msm_otg_setclk(int on)
{
if (on) {
if (!the_msm_otg->pdata->core_clk_always_on_workaround) {
clk_prepare_enable(the_msm_otg->core_clk);
- //clk_prepare_enable(the_msm_otg->pclk);
+
}
}
else {
if (!the_msm_otg->pdata->core_clk_always_on_workaround) {
clk_disable_unprepare(the_msm_otg->core_clk);
- //clk_disable_unprepare(the_msm_otg->pclk);
+
}
}
return 0;
}
EXPORT_SYMBOL(msm_otg_setclk);
-/*HTC_WIFI_END*/
static int msm_otg_resume(struct msm_otg *motg)
{
@@ -1140,6 +1175,12 @@
USBH_DEBUG("exit phy power collapse...\n");
}
+
+ if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
+ msm_hsusb_mhl_switch_enable(motg, 1);
+ msm_hsusb_config_vddcx(1);
+ }
+
if (motg->lpm_flags & PHY_RETENTIONED) {
msm_hsusb_mhl_switch_enable(motg, 1);
msm_hsusb_config_vddcx(1);
@@ -1210,22 +1251,6 @@
return 0;
}
#endif
-/*
-static int msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
-{
- if (!psy)
- goto psy_not_supported;
-
- if (host_mode)
- power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
- else
- power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
-
-psy_not_supported:
- dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
- return -ENXIO;
-}
-*/
static int msm_otg_notify_chg_type(struct msm_otg *motg)
{
static int charger_type;
@@ -1354,6 +1379,21 @@
if (!otg->host)
return;
+ if (USB_disabled) {
+ if (stop_usb_host == TRY_STOP_HOST_STATE) {
+ USBH_INFO("[USB_disabled] %s(%d) to stop host \n", __func__ , on);
+ stop_usb_host = STOP_HOST_STATE;
+ } else {
+ USBH_INFO("[USB_disabled] %s(%d) return\n", __func__ , on);
+
+ if (on) {
+ re_enable_host = TRY_ENABLE_HOST_STATE;
+ stop_usb_host = STOP_HOST_STATE;
+ }
+ return;
+ }
+ }
+
hcd = bus_to_hcd(otg->host);
if (on) {
@@ -1531,15 +1571,6 @@
USBH_INFO("Host mode is not supported\n");
return -ENODEV;
}
-/*
- if (!motg->pdata->vbus_power && host) {
- vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
- if (IS_ERR(vbus_otg)) {
- pr_err("Unable to get vbus_otg\n");
- return -ENODEV;
- }
- }
-*/
if (!host) {
USB_WARNING("%s: no host\n", __func__);
@@ -1631,6 +1662,27 @@
}
+static void usb_disable_work(struct work_struct *w)
+{
+ struct msm_otg *motg = the_msm_otg;
+ struct usb_phy *usb_phy = &motg->phy;
+ USBH_INFO("%s\n", __func__);
+ motg->chg_type = USB_DCP_CHARGER;
+ motg->chg_state = USB_CHG_STATE_DETECTED;
+ msm_otg_start_peripheral(usb_phy->otg, 0);
+ usb_phy->state = OTG_STATE_B_IDLE;
+ queue_work(system_nrt_wq, &motg->sm_work);
+}
+
+static void msm_otg_notify_usb_disabled(void)
+{
+ struct msm_otg *motg = the_msm_otg;
+ struct usb_phy *usb_phy = &motg->phy;
+ USBH_INFO("%s\n", __func__);
+ usb_gadget_vbus_disconnect(usb_phy->otg->gadget);
+ queue_work(system_nrt_wq, &motg->usb_disable_work);
+}
+
static int msm_otg_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
@@ -2047,6 +2099,8 @@
udelay(20);
break;
case SNPS_28NM_INTEGRATED_PHY:
+
+ ulpi_write(phy, 0x6, 0xC);
/* Clear charger detecting control bits */
ulpi_write(phy, 0x1F, 0x86);
/* Clear alt interrupt latch and enable bits */
@@ -2077,6 +2131,8 @@
/* Clear alt interrupt latch and enable bits */
ulpi_write(phy, 0x1F, 0x92);
ulpi_write(phy, 0x1F, 0x95);
+
+ ulpi_write(phy, 0x6, 0xB);
break;
default:
break;
@@ -2104,8 +2160,8 @@
}
}
-#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
-#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
+#define MSM_CHG_DCD_TIMEOUT (750 * HZ/1000) /* 750 msec */
+#define MSM_CHG_DCD_POLL_TIME (50 * HZ/1000) /* 50 msec */
#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
static void msm_chg_detect_work(struct work_struct *w)
@@ -2115,10 +2171,13 @@
bool is_dcd = false, tmout, vout, is_aca;
u32 line_state, dm_vlgc;
unsigned long delay;
-
USBH_INFO("%s: state:%s\n", __func__,
chg_state_string(motg->chg_state));
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ if (otg->phy->state >= OTG_STATE_A_IDLE && cable_get_accessory_type() != DOCK_STATE_HOST_CHG_DOCK) {
+#else
if (otg->phy->state >= OTG_STATE_A_IDLE) {
+#endif
motg->chg_state = USB_CHG_STATE_UNDEFINED;
USBH_INFO("%s: usb host, charger state:%s\n", __func__, chg_state_string(motg->chg_state));
if (motg->connect_type != CONNECT_TYPE_NONE) {
@@ -2127,11 +2186,11 @@
}
return;
}
+
switch (motg->chg_state) {
case USB_CHG_STATE_UNDEFINED:
msm_chg_block_on(motg);
- if (motg->pdata->enable_dcd)
- msm_chg_enable_dcd(motg);
+ msm_chg_enable_dcd(motg);
msm_chg_enable_aca_det(motg);
motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
motg->dcd_time = 0;
@@ -2151,12 +2210,11 @@
break;
}
}
- if (motg->pdata->enable_dcd)
- is_dcd = msm_chg_check_dcd(motg);
- tmout = ++motg->dcd_time == MSM_CHG_DCD_MAX_RETRIES;
+ is_dcd = msm_chg_check_dcd(motg);
+ motg->dcd_time += MSM_CHG_DCD_POLL_TIME;
+ tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT;
if (is_dcd || tmout) {
- if (motg->pdata->enable_dcd)
- msm_chg_disable_dcd(motg);
+ msm_chg_disable_dcd(motg);
msm_chg_enable_primary_det(motg);
delay = MSM_CHG_PRIMARY_DET_TIME;
motg->chg_state = USB_CHG_STATE_DCD_DONE;
@@ -2168,16 +2226,20 @@
vout = msm_chg_check_primary_det(motg);
line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
dm_vlgc = line_state & PORTSC_LS_DM;
+ USBH_INFO("line_state = %x\n",line_state);
if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
if (test_bit(ID_A, &motg->inputs)) {
motg->chg_type = USB_ACA_DOCK_CHARGER;
motg->chg_state = USB_CHG_STATE_DETECTED;
+ motg->connect_type = CONNECT_TYPE_UNKNOWN;
delay = 0;
break;
}
if (line_state) { /* DP > VLGC */
motg->chg_type = USB_PROPRIETARY_CHARGER;
motg->chg_state = USB_CHG_STATE_DETECTED;
+ motg->connect_type = CONNECT_TYPE_AC;
+ USBH_INFO("DP > VLGC\n");
delay = 0;
} else {
msm_chg_enable_secondary_det(motg);
@@ -2188,32 +2250,39 @@
if (test_bit(ID_A, &motg->inputs)) {
motg->chg_type = USB_ACA_A_CHARGER;
motg->chg_state = USB_CHG_STATE_DETECTED;
+ motg->connect_type = CONNECT_TYPE_UNKNOWN;
delay = 0;
break;
}
- if (line_state) /* DP > VLGC or/and DM > VLGC */
+ if (line_state) { /* DP > VLGC or/and DM > VLGC */
motg->chg_type = USB_PROPRIETARY_CHARGER;
- else
+ motg->connect_type = CONNECT_TYPE_AC;
+ USBH_INFO("DP > VLGC or/and DM > VLGC\n");
+ } else {
motg->chg_type = USB_SDP_CHARGER;
+ motg->connect_type = CONNECT_TYPE_UNKNOWN;
+ }
motg->chg_state = USB_CHG_STATE_DETECTED;
- motg->connect_type = CONNECT_TYPE_UNKNOWN;
delay = 0;
}
break;
case USB_CHG_STATE_PRIMARY_DONE:
vout = msm_chg_check_secondary_det(motg);
- if (vout)
+ if (vout) {
motg->chg_type = USB_DCP_CHARGER;
- else
+ motg->connect_type = CONNECT_TYPE_AC;
+ } else {
motg->chg_type = USB_CDP_CHARGER;
- motg->connect_type = CONNECT_TYPE_AC;
+ motg->connect_type = CONNECT_TYPE_USB;
+ }
motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
- /* fall through */
+
case USB_CHG_STATE_SECONDARY_DONE:
motg->chg_state = USB_CHG_STATE_DETECTED;
case USB_CHG_STATE_DETECTED:
+ msm_otg_notify_chg_type(motg);
msm_chg_block_off(motg);
msm_chg_enable_aca_det(motg);
/*
@@ -2330,6 +2399,7 @@
__func__, motg->phy.state);
return;
}
+ mutex_lock(&smwork_sem);
pm_runtime_resume(otg->phy->dev);
pr_debug("%s work\n", otg_state_string(otg->phy->state));
switch (otg->phy->state) {
@@ -2356,7 +2426,11 @@
clear_bit(B_BUS_REQ, &motg->inputs);
set_bit(A_BUS_REQ, &motg->inputs);
otg->phy->state = OTG_STATE_A_IDLE;
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ if (motg->connect_type != CONNECT_TYPE_NONE && cable_get_accessory_type() != DOCK_STATE_HOST_CHG_DOCK && motg->connect_type != CONNECT_TYPE_CLEAR) {
+#else
if (motg->connect_type != CONNECT_TYPE_NONE) {
+#endif
motg->connect_type = CONNECT_TYPE_NONE;
queue_work(motg->usb_wq, &motg->notifier_work);
}
@@ -2404,27 +2478,13 @@
OTG_STATE_B_PERIPHERAL;
break;
case USB_SDP_CHARGER:
- /* Change USB SDP charger current from 100mA to 500mA
- * msm_otg_notify_charger(motg, IUNIT);
- */
- if (USB_disabled) {
- USBH_INFO("Fake Sleep: disable USB function\n");
- /* Enable VDP_SRC */
- ulpi_write(otg->phy, 0x2, 0x85);
- msm_otg_notify_charger(motg,IDEV_CHG_MIN);
- if (motg->reset_phy_before_lpm)
- msm_otg_reset(otg->phy);
- pm_runtime_put_noidle(otg->phy->dev);
- pm_runtime_suspend(otg->phy->dev);
- } else {
- /* Turn off VDP_SRC */
- ulpi_write(otg->phy, 0x3, 0x86);
- msm_otg_notify_charger(motg, IDEV_CHG_MIN);
- msm_otg_start_peripheral(otg, 1);
- otg->phy->state = OTG_STATE_B_PERIPHERAL;
- motg->ac_detect_count = 0;
- queue_delayed_work(system_nrt_wq, &motg->ac_detect_work, 3 * HZ);
- }
+ /* Turn off VDP_SRC */
+ ulpi_write(otg->phy, 0x3, 0x86);
+ msm_otg_notify_charger(motg, IDEV_CHG_MIN);
+ msm_otg_start_peripheral(otg, 1);
+ otg->phy->state = OTG_STATE_B_PERIPHERAL;
+ motg->ac_detect_count = 0;
+ queue_delayed_work(system_nrt_wq, &motg->ac_detect_work, 2 * HZ);
break;
default:
break;
@@ -2499,10 +2559,12 @@
queue_work(motg->usb_wq, &motg->notifier_work);
}
- // if (check_htc_mode_status() != NOT_ON_AUTOBOT) {
- // htc_mode_enable(0);
- // android_switch_default();
- // }
+#if 0
+ if (check_htc_mode_status() != NOT_ON_AUTOBOT) {
+ htc_mode_enable(0);
+ android_switch_default();
+ }
+#endif
USBH_INFO("!id || id_a/b || !b_sess_vld\n");
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
@@ -2660,10 +2722,19 @@
*/
usleep_range(10000, 12000);
/* ACA: ID_A: Stop charging untill enumeration */
- if (test_bit(ID_A, &motg->inputs))
+ if (test_bit(ID_A, &motg->inputs)) {
msm_otg_notify_charger(motg, 0);
- else
+ }
+ else {
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ if (htc_otg_vbus == 1 && cable_get_accessory_type() == DOCK_STATE_HOST_CHG_DOCK)
+ msm_hsusb_vbus_power(motg, 0);
+ else
+ msm_hsusb_vbus_power(motg, 1);
+#else
msm_hsusb_vbus_power(motg, 1);
+#endif
+ }
msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
} else {
USBH_INFO("No session requested\n");
@@ -2752,7 +2823,22 @@
if (TA_WAIT_BCON < 0)
pm_runtime_put_sync(otg->phy->dev);
} else if (!test_bit(ID, &motg->inputs)) {
- msm_hsusb_vbus_power(motg, 1);
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ if (cable_get_accessory_type() != DOCK_STATE_HOST_CHG_DOCK)
+ msm_hsusb_vbus_power(motg, 1);
+#endif
+ }
+
+ if (USB_disabled && stop_usb_host != STOP_HOST_STATE) {
+ USBH_INFO("[USB_disabled] disable USB Host function\n");
+ stop_usb_host = TRY_STOP_HOST_STATE;
+ re_enable_host = TRY_ENABLE_HOST_STATE;
+ msm_otg_start_host(otg, 0);
+ } else if (!USB_disabled && re_enable_host == TRY_ENABLE_HOST_STATE) {
+ USBH_INFO("[USB_disabled] re-enable USB Host function\n");
+ re_enable_host = DEFAULT_STATE;
+ stop_usb_host = DEFAULT_STATE;
+ msm_otg_start_host(otg, 1);
}
break;
case OTG_STATE_A_HOST:
@@ -2810,8 +2896,23 @@
} else if (!test_bit(ID, &motg->inputs)) {
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
+#ifdef CONFIG_USB_OTG_HOST_CHG
+ if (htc_otg_vbus == 1 && cable_get_accessory_type() == DOCK_STATE_HOST_CHG_DOCK)
+ msm_hsusb_vbus_power(motg, 0);
+ else {
+ msm_otg_notify_charger(motg, 0);
+ msm_hsusb_vbus_power(motg, 1);
+ }
+#else
msm_otg_notify_charger(motg, 0);
msm_hsusb_vbus_power(motg, 1);
+#endif
+ if (USB_disabled) {
+ USBH_INFO("[USB_disabled] disable USB Host function\n");
+ re_enable_host = TRY_ENABLE_HOST_STATE;
+ stop_usb_host = TRY_STOP_HOST_STATE;
+ msm_otg_start_host(otg, 0);
+ }
}
break;
case OTG_STATE_A_SUSPEND:
@@ -2855,6 +2956,13 @@
if (TA_WAIT_BCON > 0)
msm_otg_start_timer(motg, TA_WAIT_BCON,
A_WAIT_BCON);
+
+ if (!USB_disabled && re_enable_host == TRY_ENABLE_HOST_STATE) {
+ USBH_INFO("[USB_disabled] re-enable USB Host function\n");
+ re_enable_host = DEFAULT_STATE;
+ stop_usb_host = DEFAULT_STATE;
+ msm_otg_start_host(otg, 1);
+ }
} else if (test_bit(ID_A, &motg->inputs)) {
msm_hsusb_vbus_power(motg, 0);
msm_otg_notify_charger(motg,
@@ -2931,6 +3039,7 @@
default:
break;
}
+ mutex_unlock(&smwork_sem);
if (work)
queue_work(system_nrt_wq, &motg->sm_work);
}
@@ -2985,27 +3094,6 @@
work = 1;
} else if (otgsc & OTGSC_BSVIS) {
writel_relaxed(otgsc, USB_OTGSC);
- /*
- * BSV interrupt comes when operating as an A-device
- * (VBUS on/off).
- * But, handle BSV when charger is removed from ACA in ID_A
- */
- /*
- if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
- !test_bit(ID_A, &motg->inputs))
- return IRQ_HANDLED;
- if (otgsc & OTGSC_BSV) {
- pr_debug("BSV set\n");
- set_bit(B_SESS_VLD, &motg->inputs);
- } else {
- pr_debug("BSV clear\n");
- clear_bit(B_SESS_VLD, &motg->inputs);
- clear_bit(A_BUS_SUSPEND, &motg->inputs);
-
- msm_chg_check_aca_intr(motg);
- }
- work = 1;
- */
} else if (usbsts & STS_PCI) {
pc = readl_relaxed(USB_PORTSC);
pr_debug("portsc = %x\n", pc);
@@ -3099,29 +3187,25 @@
return ret;
}
-
/* The dedicated 9V detection GPIO will be high if VBUS is in and over 6V.
* Since D+/D- status is not involved, there is no timing issue between
* D+/D- and VBUS. 9V AC should NOT be found here.
*/
static void ac_detect_expired_work(struct work_struct *w)
{
- u32 delay = 0;
+ u32 delay = 0, line_state;
struct msm_otg *motg = the_msm_otg;
struct usb_phy *usb_phy = &motg->phy;
- USBH_INFO("%s: count = %d, connect_type = %d\n", __func__,
- motg->ac_detect_count, motg->connect_type);
+ line_state = readl(USB_PORTSC) & PORTSC_LS;
+ USBH_INFO("%s: count = %d, connect_type = %d, line_state = %x\n", __func__,
+ motg->ac_detect_count, motg->connect_type,line_state << 10);
- if (motg->connect_type == CONNECT_TYPE_USB || motg->ac_detect_count >= 3)
+ if (motg->connect_type == CONNECT_TYPE_USB || motg->ac_detect_count >= 5)
return;
/* detect shorted D+/D-, indicating AC power */
- if ((readl(USB_PORTSC) & PORTSC_LS) != PORTSC_LS) {
- /* Some carkit can't be recognized as AC mode.
- * Add SW solution here to notify battery driver should
- * work as AC charger when car mode activated.
- */
+ if (line_state != PORTSC_LS) {
#ifdef CONFIG_CABLE_DETECT_ACCESSORY
if (cable_get_accessory_type() == DOCK_STATE_CAR
||cable_get_accessory_type() == DOCK_STATE_AUDIO_DOCK) {
@@ -3134,16 +3218,40 @@
msm_otg_start_peripheral(usb_phy->otg, 0);
usb_phy->state = OTG_STATE_B_IDLE;
queue_work(system_nrt_wq, &motg->sm_work);
-
queue_work(motg->usb_wq, &motg->notifier_work);
return;
}
+ {
+ int dock_result = check_three_pogo_dock();
+ if (dock_result == 2) {
+ USBH_INFO("three pogo dock AC type\n");
+ motg->chg_type = USB_DCP_CHARGER;
+ motg->chg_state = USB_CHG_STATE_DETECTED;
+ motg->connect_type = CONNECT_TYPE_AC;
+ motg->ac_detect_count = 0;
+
+ msm_otg_start_peripheral(usb_phy->otg, 0);
+ usb_phy->state = OTG_STATE_B_IDLE;
+ queue_work(system_nrt_wq, &motg->sm_work);
+ queue_work(motg->usb_wq, &motg->notifier_work);
+ return;
+ } else if (dock_result == 1) {
+ USBH_INFO("three pogo dock USB type\n");
+ motg->chg_type = USB_INVALID_CHARGER;
+ motg->chg_state = USB_CHG_STATE_DETECTED;
+ motg->connect_type = CONNECT_TYPE_NONE;
+ motg->ac_detect_count = 0;
+
+ msm_otg_start_peripheral(usb_phy->otg, 0);
+ usb_phy->state = OTG_STATE_B_IDLE;
+ queue_work(system_nrt_wq, &motg->sm_work);
+ queue_work(motg->usb_wq, &motg->notifier_work);
+ return;
+ }
+ }
#endif
- motg->ac_detect_count++;
- if (motg->ac_detect_count == 1)
- delay = 5 * HZ;
- else if (motg->ac_detect_count == 2)
- delay = 10 * HZ;
+ if (motg->ac_detect_count++ < 5)
+ delay = 2 * HZ;
queue_delayed_work(system_nrt_wq, &motg->ac_detect_work, delay);
} else {
@@ -3161,11 +3269,12 @@
}
}
+#ifndef CONFIG_CABLE_DETECT_8X60
static void htc_vbus_notify(int online)
{
cable_detection_vbus_irq_handler();
- /*cable_detection_vbus_notify(online);*/
}
+#endif
int msm_otg_get_vbus_state(void)
{
@@ -3178,12 +3287,15 @@
struct msm_otg *motg = the_msm_otg;
struct usb_otg *otg = motg->phy.otg;
USBH_INFO("%s: %d\n", __func__, online);
-
htc_otg_vbus = online;
+#ifdef CONFIG_USB_OTG_HOST_CHG
/* In A Host Mode, ignore received BSV interrupts */
+ if (online && otg->phy->state >= OTG_STATE_A_IDLE && cable_get_accessory_type() == DOCK_STATE_HOST_CHG_DOCK)
+ return;
+#else
if (online && otg->phy->state >= OTG_STATE_A_IDLE)
return;
-
+#endif
if (online) {
pr_debug("PMIC: BSV set\n");
set_bit(B_SESS_VLD, &motg->inputs);
@@ -3193,6 +3305,10 @@
/*USB*/
if (motg->pdata->usb_uart_switch)
motg->pdata->usb_uart_switch(0);
+ if (motg->connect_type == 0) {
+ motg->connect_type = CONNECT_TYPE_NOTIFY;
+ queue_work(motg->usb_wq, &motg->notifier_work);
+ }
} else {
pr_debug("PMIC: BSV clear\n");
clear_bit(B_SESS_VLD, &motg->inputs);
@@ -3217,6 +3333,7 @@
}
+#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
void msm_otg_set_id_state(int id)
{
struct msm_otg *motg = the_msm_otg;
@@ -3243,6 +3360,7 @@
else
msm_otg_set_id_state(1);
}
+#endif
void msm_otg_set_disable_usb(int disable_usb)
{
@@ -3250,6 +3368,8 @@
USB_disabled = disable_usb;
+ if (!disable_usb)
+ motg->chg_state = USB_CHG_STATE_UNDEFINED;
queue_work(system_nrt_wq, &motg->sm_work);
}
@@ -3606,10 +3726,12 @@
debugfs_remove_recursive(msm_otg_dbg_root);
}
+#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
static struct t_usb_host_status_notifier usb_host_status_notifier = {
.name = "usb_host",
.func = usb_host_cable_detect,
};
+#endif
static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
static struct platform_device *msm_otg_add_pdev(
@@ -3981,6 +4103,7 @@
wake_lock_init(&motg->cable_detect_wlock, WAKE_LOCK_SUSPEND, "msm_usb_cable");
msm_otg_init_timer(motg);
INIT_WORK(&motg->sm_work, msm_otg_sm_work);
+ INIT_WORK(&motg->usb_disable_work, usb_disable_work);
INIT_WORK(&motg->notifier_work, send_usb_connect_notify);
INIT_DELAYED_WORK(&motg->ac_detect_work, ac_detect_expired_work);
INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
@@ -4000,6 +4123,7 @@
phy->set_power = msm_otg_set_power;
phy->set_suspend = msm_otg_set_suspend;
phy->notify_usb_attached = msm_otg_notify_usb_attached;
+ phy->notify_usb_disabled = msm_otg_notify_usb_disabled;
phy->io_ops = &msm_otg_io_ops;
phy->send_event = msm_otg_send_event;
phy->otg->send_event = msm_otg_send_event2;
@@ -4028,12 +4152,7 @@
goto remove_phy;
}
} else {
- /* HTC hw design doesn't need the following code. mask it when hw is not EVM*/
- /*
- ret = -ENODEV;
- dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
- goto remove_otg;
- */
+
dev_dbg(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist. Maybe monitor id pin by GPIO");
}
}
@@ -4049,17 +4168,24 @@
dev_dbg(&pdev->dev, "mode debugfs file is"
"not available\n");
- if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
- pm8921_charger_register_vbus_sn(&htc_vbus_notify/*&msm_otg_set_vbus_state*/);
+ if (motg->pdata->otg_control == OTG_PMIC_CONTROL) {
+#ifdef CONFIG_CABLE_DETECT_8X60
+ pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
+#else
+ pm8921_charger_register_vbus_sn(&htc_vbus_notify);
+#endif
+ }
+#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
usb_host_detect_register_notifier(&usb_host_status_notifier);
+#endif
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
#if 0
if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
(!(motg->pdata->mode == USB_OTG) ||
motg->pdata->pmic_id_irq))
- motg->caps = /*ALLOW_PHY_POWER_COLLAPSE |*/ ALLOW_PHY_RETENTION;
+ motg->caps = ALLOW_PHY_RETENTION;
#endif
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index aaf0a05..24dc1de 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -220,7 +220,7 @@
bool mhl_enable;
bool disable_reset_on_disconnect;
#ifdef CONFIG_MACH_HTC
- bool enable_dcd;
+ bool enable_dcd;
#endif
bool enable_lpm_on_dev_suspend;
bool core_clk_always_on_workaround;
@@ -398,6 +398,7 @@
int connect_type_ready;
struct workqueue_struct *usb_wq;
struct delayed_work ac_detect_work;
+ struct work_struct usb_disable_work;
int ac_detect_count;
int reset_phy_before_lpm;
#endif
@@ -407,6 +408,9 @@
u8 active_tmout;
struct hrtimer timer;
enum usb_vdd_type vdd_type;
+#ifdef CONFIG_MACH_HTC
+ struct delayed_work init_work;
+#endif
};
struct msm_hsic_host_platform_data {
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index a584d24..9b58245d 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -161,6 +161,7 @@
enum usb_otg_event event);
void (*notify_usb_attached)(void);
+ void (*notify_usb_disabled)(void);
#endif
};