Update Android USB Gadgets to latest from the Legend tree
/drivers/usb/gadget/msm72k_udc.c
blob:cf5a2bc77f74aaff7fb388568c0e992fa5d3acb3 -> blob:ecb2d35f5dbb84a5e242ec04a5d1ee7fcac93cc8
--- drivers/usb/gadget/msm72k_udc.c
+++ drivers/usb/gadget/msm72k_udc.c
@@ -49,11 +49,7 @@
#ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC
#include <mach/htc_headset_mgr.h>
#endif
-#include <linux/wakelock.h>
-#include <mach/perflock.h>
-
-static struct wake_lock vbus_idle_wake_lock;
-static struct perf_lock usb_perf_lock;
+#include <mach/clk.h>
static const char driver_name[] = "msm72k_udc";
@@ -85,11 +81,14 @@ static struct usb_info *the_usb_info;
static int vbus;
static int use_mfg_serialno;
static char mfg_df_serialno[16];
+static int disable_charger;
-#ifdef CONFIG_USB_ACCESSORY_DETECT
+#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT)
#ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC
extern int htc_get_usb_accessory_adc_level(uint32_t *buffer);
#endif
+
+
static struct switch_dev dock_switch = {
.name = "dock",
};
@@ -99,6 +98,12 @@ static struct switch_dev dock_switch = {
#define DOCK_STATE_CAR (1 << 1)
#endif
+#include <linux/wakelock.h>
+#include <mach/perflock.h>
+
+static struct wake_lock vbus_idle_wake_lock;
+static struct perf_lock usb_perf_lock;
+
struct msm_request {
struct usb_request req;
@@ -148,6 +153,10 @@ static void check_charger(struct work_st
#ifdef CONFIG_USB_ACCESSORY_DETECT
static void accessory_detect_work(struct work_struct *w);
#endif
+#ifdef CONFIG_DOCK_ACCESSORY_DETECT
+static void dock_detect_work(struct work_struct *w);
+static void dock_detect_init(struct usb_info *ui);
+#endif
extern int android_switch_function(unsigned func);
extern int android_show_function(char *buf);
extern void android_set_serialno(char *serialno);
@@ -206,6 +215,10 @@ struct usb_info {
void (*phy_reset)(void);
void (*hw_reset)(bool en);
void (*usb_uart_switch)(int);
+ void (*serial_debug_gpios)(int);
+ void (*usb_hub_enable)(bool);
+ int (*china_ac_detect)(void);
+ void (*disable_usb_charger)(void);
/* for notification when USB is connected or disconnected */
void (*usb_connected)(int);
@@ -214,6 +227,7 @@ struct usb_info {
struct work_struct work;
struct delayed_work chg_work;
struct work_struct detect_work;
+ struct work_struct dock_work;
struct work_struct notifier_work;
unsigned phy_status;
unsigned phy_fail_count;
@@ -238,10 +252,13 @@ struct usb_info {
u8 in_lpm;
/* for accessory detection */
+ bool dock_detect;
u8 accessory_detect;
u8 mfg_usb_carkit_enable;
int idpin_irq;
+ int dockpin_irq;
int usb_id_pin_gpio;
+ int dock_pin_gpio;
void (*config_usb_id_gpios)(bool output_enable);
/* 0: none, 1: carkit, 2: usb headset */
u8 accessory_type;
@@ -332,7 +349,7 @@ static int ulpi_write(struct usb_info *u
USB_ULPI_VIEWPORT);
/* wait for completion */
- while((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
+ while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
if (timeout == 0) {
printk(KERN_ERR "ulpi_write: timeout\n");
@@ -812,6 +829,10 @@ static void handle_setup(struct usb_info
case J_TEST:
case K_TEST:
case SE0_NAK_TEST:
+ if (!ui->test_mode) {
+ disable_charger = 1;
+ queue_delayed_work(ui->usb_wq, &ui->chg_work, 0);
+ }
case TST_PKT_TEST:
ui->test_mode = ctl.wIndex;
goto ack;
@@ -1326,13 +1347,17 @@ static ssize_t store_mfg_carkit_enable(s
static DEVICE_ATTR(usb_mfg_carkit_enable, 0644,
show_mfg_carkit_enable, store_mfg_carkit_enable);
+#endif
+#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT)
static ssize_t dock_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_info *ui = the_usb_info;
if (ui->accessory_type == 1)
return sprintf(buf, "online\n");
+ else if (ui->accessory_type == 3) /*desk dock*/
+ return sprintf(buf, "online\n");
else
return sprintf(buf, "offline\n");
}
@@ -1369,6 +1394,13 @@ static void usb_prepare(struct usb_info
#ifdef CONFIG_USB_ACCESSORY_DETECT
INIT_WORK(&ui->detect_work, accessory_detect_work);
#endif
+#ifdef CONFIG_DOCK_ACCESSORY_DETECT
+ if (ui->dock_detect) {
+ INIT_WORK(&ui->dock_work, dock_detect_work);
+ dock_detect_init(ui);
+ }
+#endif
+
INIT_WORK(&ui->notifier_work, send_usb_connect_notify);
INIT_DELAYED_WORK(&ui->chg_work, check_charger);
@@ -1408,6 +1440,7 @@ static void usb_prepare(struct usb_info
if (ret != 0)
printk(KERN_WARNING "dev_attr_usb_mfg_carkit_enable failed\n");
#endif
+
}
static int usb_wakeup_phy(struct usb_info *ui)
@@ -1550,6 +1583,18 @@ static void usb_start(struct usb_info *u
spin_lock_irqsave(&ui->lock, flags);
ui->flags |= USB_FLAG_START;
+/*if msm_hsusb_set_vbus_state set 1, but usb did not init, the ui =NULL, */
+/*it would cause reboot with usb, it did not swith to USB and ADB fail*/
+/*So when USB start, check again*/
+ if (vbus) {
+ ui->flags |= USB_FLAG_VBUS_ONLINE;
+ } else {
+ ui->flags |= USB_FLAG_VBUS_OFFLINE;
+ }
+ /* online->switch to USB, offline->switch to uart */
+ if (ui->usb_uart_switch)
+ ui->usb_uart_switch(!vbus);
+
queue_work(ui->usb_wq, &ui->work);
spin_unlock_irqrestore(&ui->lock, flags);
}
@@ -1647,6 +1692,77 @@ static void usb_lpm_exit(struct usb_info
}
}
+#ifdef CONFIG_DOCK_ACCESSORY_DETECT
+static irqreturn_t dock_interrupt(int irq, void *data)
+{
+ struct usb_info *ui = data;
+ disable_irq_nosync(ui->dockpin_irq);
+ queue_work(ui->usb_wq, &ui->dock_work);
+ return IRQ_HANDLED;
+}
+static void dock_detect_work(struct work_struct *w)
+{
+ struct usb_info *ui = container_of(w, struct usb_info, dock_work);
+ int value;
+
+ value = gpio_get_value(ui->dock_pin_gpio);
+
+ if (value == 0) {
+ set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_HIGH);
+ switch_set_state(&dock_switch, DOCK_STATE_DESK);
+ ui->accessory_type = 3;
+ printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_DESK);
+ } else {
+ set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW);
+ switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
+ ui->accessory_type = 0;
+ printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_UNDOCKED);
+ }
+ enable_irq(ui->dockpin_irq);
+
+
+}
+static void dock_detect_init(struct usb_info *ui)
+{
+ int ret;
+
+ if (ui->dock_pin_gpio == 0)
+ return;
+ if (ui->dockpin_irq == 0)
+ ui->dockpin_irq = gpio_to_irq(ui->dock_pin_gpio);
+
+ ret = request_irq(ui->dockpin_irq, dock_interrupt,
+ IRQF_TRIGGER_LOW,
+ "dock_irq", ui);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: request_irq failed\n", __func__);
+ return;
+ }
+ printk(KERN_INFO "%s: dock irq %d\n", __func__,
+ ui->dockpin_irq);
+ ret = set_irq_wake(ui->dockpin_irq, 1);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: set_irq_wake failed\n", __func__);
+ goto err;
+ }
+
+ if (switch_dev_register(&dock_switch) < 0) {
+ printk(KERN_ERR "usb: fail to register dock switch!\n");
+ goto err;
+ }
+
+ ret = device_create_file(dock_switch.dev, &dev_attr_status);
+ if (ret != 0)
+ printk(KERN_WARNING "dev_attr_status failed\n");
+
+ return;
+
+err:
+ free_irq(ui->dockpin_irq, 0);
+}
+#endif
+
+
#ifdef CONFIG_USB_ACCESSORY_DETECT
static void carkit_detect(struct usb_info *ui)
{
@@ -1704,7 +1820,7 @@ static void accessory_detect_by_adc(stru
if (adc_value >= 0x2112 && adc_value <= 0x3D53) {
printk(KERN_INFO "usb: headset inserted\n");
ui->accessory_type = 2;
- headset_ext_detect(USB_HEADSET);
+ headset_ext_detect(USB_AUDIO_OUT);
} else if (adc_value >= 0x88A && adc_value <= 0x1E38) {
printk(KERN_INFO "usb: carkit inserted\n");
ui->accessory_type = 1;
@@ -1718,7 +1834,7 @@ static void accessory_detect_by_adc(stru
} else {
if (ui->accessory_type == 2) {
printk(KERN_INFO "usb: headset removed\n");
- headset_ext_detect(NO_DEVICE);
+ headset_ext_detect(USB_NO_HEADSET);
} else if (ui->accessory_type == 1) {
printk(KERN_INFO "usb: carkit removed\n");
switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
@@ -1770,7 +1886,8 @@ static void accessory_detect_init(struct
if (ui->usb_id_pin_gpio == 0)
return;
- ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio);
+ if (ui->idpin_irq == 0)
+ ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio);
ret = request_irq(ui->idpin_irq, usbid_interrupt,
IRQF_TRIGGER_LOW,
@@ -1790,9 +1907,11 @@ static void accessory_detect_init(struct
printk(KERN_ERR "usb: fail to register dock switch!\n");
goto err;
}
+
ret = device_create_file(dock_switch.dev, &dev_attr_status);
if (ret != 0)
printk(KERN_WARNING "dev_attr_status failed\n");
+
return;
err:
free_irq(ui->idpin_irq, 0);
@@ -1825,6 +1944,13 @@ static void charger_detect(struct usb_in
static void check_charger(struct work_struct *w)
{
struct usb_info *ui = container_of(w, struct usb_info, chg_work.work);
+ if (disable_charger) {
+ printk(KERN_INFO "usb: disable charger\n");
+ if (ui->disable_usb_charger)
+ ui->disable_usb_charger();
+ disable_charger = 0;
+ return;
+ }
/* unknown charger */
if (vbus && ui->connect_type == CONNECT_TYPE_UNKNOWN)
queue_work(ui->usb_wq, &ui->notifier_work);
@@ -1836,6 +1962,7 @@ static void usb_do_work(struct work_stru
unsigned long iflags;
unsigned flags, _vbus;
+
for (;;) {
spin_lock_irqsave(&ui->lock, iflags);
flags = ui->flags;
@@ -1852,6 +1979,8 @@ static void usb_do_work(struct work_stru
pr_info("hsusb: IDLE -> ONLINE\n");
usb_lpm_exit(ui);
usb_reset(ui);
+
+ if (!ui->china_ac_detect)
charger_detect(ui);
ui->state = USB_STATE_ONLINE;
@@ -1926,6 +2055,8 @@ static void usb_do_work(struct work_stru
pr_info("hsusb: OFFLINE -> ONLINE\n");
usb_lpm_exit(ui);
usb_reset(ui);
+
+ if (!ui->china_ac_detect)
charger_detect(ui);
ui->state = USB_STATE_ONLINE;
@@ -1944,6 +2075,7 @@ void msm_hsusb_set_vbus_state(int online
{
unsigned long flags = 0;
struct usb_info *ui = the_usb_info;
+ int is_china_ac;
printk(KERN_INFO "%s: %d\n", __func__, online);
if (ui)
@@ -1956,9 +2088,49 @@ void msm_hsusb_set_vbus_state(int online
} else {
ui->flags |= USB_FLAG_VBUS_OFFLINE;
}
- /* online->switch to USB, offline->switch to uart */
- if (ui->usb_uart_switch)
- ui->usb_uart_switch(!online);
+
+ if (online) {
+ if (ui->china_ac_detect) {
+ is_china_ac = ui->china_ac_detect();
+
+ if (is_china_ac) {
+ ui->connect_type = CONNECT_TYPE_AC;
+ queue_work(ui->usb_wq, &ui->notifier_work);
+ usb_lpm_enter(ui);
+ printk(KERN_INFO "usb: AC charger\n");
+ } else {
+ ui->connect_type = CONNECT_TYPE_UNKNOWN;
+ queue_delayed_work(ui->usb_wq, &ui->chg_work,
+ DELAY_FOR_CHECK_CHG);
+ printk(KERN_INFO "usb: not AC charger\n");
+ }
+ }
+
+
+ /*set uart to gpo*/
+ if (ui->serial_debug_gpios)
+ ui->serial_debug_gpios(0);
+ /*turn on USB HUB*/
+ if (ui->usb_hub_enable) {
+ ui->usb_hub_enable(1);
+ }
+
+ /*USB*/
+ if (ui->usb_uart_switch)
+ ui->usb_uart_switch(0);
+ } else {
+ /*turn off USB HUB*/
+ if (ui->usb_hub_enable)
+ ui->usb_hub_enable(0);
+
+ /*UART*/
+ if (ui->usb_uart_switch)
+ ui->usb_uart_switch(1);
+ /*configure uart pin to alternate function*/
+ if (ui->serial_debug_gpios)
+ ui->serial_debug_gpios(1);
+ }
+
queue_work(ui->usb_wq, &ui->work);
}
}
@@ -2379,6 +2551,10 @@ static int msm72k_probe(struct platform_
ui->phy_init_seq = pdata->phy_init_seq;
ui->usb_connected = pdata->usb_connected;
ui->usb_uart_switch = pdata->usb_uart_switch;
+ ui->serial_debug_gpios = pdata->serial_debug_gpios;
+ ui->usb_hub_enable = pdata->usb_hub_enable;
+ ui->china_ac_detect = pdata->china_ac_detect;
+ ui->disable_usb_charger = pdata->disable_usb_charger;
ui->accessory_detect = pdata->accessory_detect;
printk(KERN_INFO "usb: accessory detect %d\n",
@@ -2386,6 +2562,15 @@ static int msm72k_probe(struct platform_
ui->usb_id_pin_gpio = pdata->usb_id_pin_gpio;
printk(KERN_INFO "usb: id_pin_gpio %d\n",
pdata->usb_id_pin_gpio);
+
+ ui->dock_detect = pdata->dock_detect;
+ printk(KERN_INFO "usb: dock detect %d\n",
+ ui->dock_detect);
+ ui->dock_pin_gpio = pdata->dock_pin_gpio;
+ printk(KERN_INFO "usb: dock pin gpio %d\n",
+ ui->dock_pin_gpio);
+
+ ui->idpin_irq = pdata->id_pin_irq;
if (pdata->config_usb_id_gpios)
ui->config_usb_id_gpios = pdata->config_usb_id_gpios;
}
@@ -2475,8 +2660,7 @@ static int msm72k_probe(struct platform_
use_mfg_serialno = 1;
wake_lock_init(&vbus_idle_wake_lock, WAKE_LOCK_IDLE, "usb_idle_lock");
perf_lock_init(&usb_perf_lock, PERF_LOCK_HIGHEST, "usb");
- }
- else
+ } else
use_mfg_serialno = 0;
strncpy(mfg_df_serialno, "000000000000", strlen("000000000000"));