diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 26b76345..f7724976 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -129,6 +129,45 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size, { } +/* + * dma_coherent_pre_ops - barrier functions for coherent memory before DMA. + * A barrier is required to ensure memory operations are complete before the + * initiation of a DMA xfer. + * If the coherent memory is Strongly Ordered + * - pre ARMv7 and 8x50 guarantees ordering wrt other mem accesses + * - ARMv7 guarantees ordering only within a 1KB block, so we need a barrier + * If coherent memory is normal then we need a barrier to prevent + * reordering + */ +static inline void dma_coherent_pre_ops(void) +{ +#if (__LINUX_ARM_ARCH__ >= 7) + dmb(); +#else + if (arch_is_coherent()) + dmb(); + else + barrier(); +#endif +} +/* + * dma_post_coherent_ops - barrier functions for coherent memory after DMA. + * If the coherent memory is Strongly Ordered we dont need a barrier since + * there are no speculative fetches to Strongly Ordered memory. + * If coherent memory is normal then we need a barrier to prevent reordering + */ +static inline void dma_coherent_post_ops(void) +{ +#if (__LINUX_ARM_ARCH__ >= 7) + dmb(); +#else + if (arch_is_coherent()) + dmb(); + else + barrier(); +#endif +} + /** * dma_alloc_coherent - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index cebfe9d0..7da0c22e 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -179,6 +179,16 @@ enum { }; void msm_hsusb_set_vbus_state(int online); +enum usb_connect_type { + CONNECT_TYPE_CLEAR = -2, + CONNECT_TYPE_UNKNOWN = -1, + CONNECT_TYPE_NONE = 0, + CONNECT_TYPE_USB, + CONNECT_TYPE_AC, + CONNECT_TYPE_9V_AC, + CONNECT_TYPE_WIRELESS, + CONNECT_TYPE_INTERNAL, +}; #define MSM_MAX_DEC_CNT 14 /* 7k target ADSP information */ diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h index bfd174f7..4036ec18 100644 --- a/arch/arm/mach-msm/include/mach/msm_hsusb.h +++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h @@ -47,8 +47,18 @@ struct msm_hsusb_platform_data { /* 1 : uart, 0 : usb */ void (*usb_uart_switch)(int); void (*config_usb_id_gpios)(bool enable); - /* val, reg pairs terminated by -1 */ - int *phy_init_seq; + void (*usb_hub_enable)(bool); + void (*serial_debug_gpios)(int); + int (*china_ac_detect)(void); + void (*disable_usb_charger)(void); + /* val, reg pairs terminated by -1 */ + int *phy_init_seq; + void (*change_phy_voltage)(int); + int (*ldo_init) (int init); + int (*ldo_enable) (int enable); + int (*rpc_connect)(int); + /* 1 : mhl, 0 : usb */ + void (*usb_mhl_switch)(bool); #ifdef CONFIG_USB_FUNCTION /* USB device descriptor fields */ @@ -74,10 +84,15 @@ struct msm_hsusb_platform_data { int num_products; struct msm_hsusb_product *products; #endif - char *serial_number; - int usb_id_pin_gpio; - bool enable_car_kit_detect; - __u8 accessory_detect; + char *serial_number; + int usb_id_pin_gpio; + int dock_pin_gpio; + int id_pin_irq; + bool enable_car_kit_detect; + __u8 accessory_detect; + bool dock_detect; + + int ac_9v_gpio; }; int usb_get_connect_type(void); diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h index e2c86c18..ca2f794c 100644 --- a/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h +++ b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h @@ -37,11 +37,30 @@ do { } while (0) #endif /* VERBOSE */ +#ifndef __LINUX_USB_COMPOSITE_H #define ERROR(fmt,args...) \ xprintk(KERN_ERR , fmt , ## args) #define INFO(fmt,args...) \ xprintk(KERN_INFO , fmt , ## args) +#endif +#define USB_ERR(fmt, args...) \ + printk(KERN_ERR "[USB:ERR] " fmt, ## args) +#define USB_WARNING(fmt, args...) \ + printk(KERN_WARNING "[USB] " fmt, ## args) +#define USB_INFO(fmt, args...) \ + printk(KERN_INFO "[USB] " fmt, ## args) +#define USB_DEBUG(fmt, args...) \ + printk(KERN_DEBUG "[USB] " fmt, ## args) + +#define USBH_ERR(fmt, args...) \ + printk(KERN_ERR "[USBH:ERR] " fmt, ## args) +#define USBH_WARNING(fmt, args...) \ + printk(KERN_WARNING "[USBH] " fmt, ## args) +#define USBH_INFO(fmt, args...) \ + printk(KERN_INFO "[USBH] " fmt, ## args) +#define USBH_DEBUG(fmt, args...) \ + printk(KERN_DEBUG "[USBH] " fmt, ## args) /*-------------------------------------------------------------------------*/ @@ -51,9 +70,12 @@ #define USB_HWDEVICE (MSM_USB_BASE + 0x000C) #define USB_HWTXBUF (MSM_USB_BASE + 0x0010) #define USB_HWRXBUF (MSM_USB_BASE + 0x0014) -#define USB_AHBBURST (MSM_USB_BASE + 0x0090) -#define USB_AHBMODE (MSM_USB_BASE + 0x0098) +#define USB_AHB_BURST (MSM_USB_BASE + 0x0090) +#define USB_AHB_MODE (MSM_USB_BASE + 0x0098) +#define USB_AHBBURST (USB_AHB_BURST) +#define USB_AHBMODE (USB_AHB_MODE) #define USB_SBUSCFG (MSM_USB_BASE + 0x0090) +#define USB_ROC_AHB_MODE (MSM_USB_BASE + 0x0090) #define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */ #define USB_HCIVERSION (MSM_USB_BASE + 0x0102) /* 16 bit */ @@ -82,12 +104,26 @@ #define USB_ENDPTCTRL(n) (MSM_USB_BASE + 0x01C0 + (4 * (n))) -#define USBCMD_RESET 2 -#define USBCMD_ATTACH 1 -#define USBCMD_ATDTW (1 << 14) +#define USBCMD_RESET 2 +#define USBCMD_ATTACH 1 +#define USBCMD_RS (1 << 0) /* run/stop bit */ +#define USBCMD_ATDTW (1 << 14) + +#define ASYNC_INTR_CTRL (1 << 29) +#define ULPI_STP_CTRL (1 << 30) +#define USBCMD_ITC(n) (n << 16) +#define USBCMD_ITC_MASK (0xFF << 16) + #define USBMODE_DEVICE 2 #define USBMODE_HOST 3 +/* Redefining SDIS bit as it defined incorrectly in ehci.h. */ +#ifdef USBMODE_SDIS +#undef USBMODE_SDIS +#endif +#define USBMODE_SDIS (1 << 4) /* stream disable */ +#define USBMODE_VBUS (1 << 5) /* vbus power select */ + struct ept_queue_head { unsigned config; @@ -138,7 +174,7 @@ struct ept_queue_item { #define STS_NAKI (1 << 16) /* */ #define STS_SLI (1 << 8) /* R/WC - suspend state entered */ #define STS_SRI (1 << 7) /* R/WC - SOF recv'd */ -#define STS_URI (1 << 6) /* R/WC - RESET recv'd - write to clear */ +#define STS_URI (1 << 6) /* R/WC - RESET recv'd */ #define STS_FRI (1 << 3) /* R/WC - Frame List Rollover */ #define STS_PCI (1 << 2) /* R/WC - Port Change Detect */ #define STS_UEI (1 << 1) /* R/WC - USB Error */ @@ -175,6 +211,38 @@ struct ept_queue_item { #define CTRL_RXT_INT (3 << 2) #define CTRL_RXT_EP_TYPE_SHIFT 2 +#if defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60) +#define ULPI_DIGOUT_CTRL 0X36 +#define ULPI_CDR_AUTORESET (1 << 1) +#else +#define ULPI_DIGOUT_CTRL 0X31 +#define ULPI_CDR_AUTORESET (1 << 5) +#endif + +#define ULPI_FUNC_CTRL_CLR (0x06) +#define ULPI_IFC_CTRL_CLR (0x09) +#define ULPI_AMPLITUDE_MAX (0x0C) +#define ULPI_OTG_CTRL (0x0B) +#define ULPI_OTG_CTRL_CLR (0x0C) +#define ULPI_INT_RISE_CLR (0x0F) +#define ULPI_INT_FALL_CLR (0x12) +#define ULPI_DEBUG_REG (0x15) +#define ULPI_SCRATCH_REG (0x16) +#define ULPI_CONFIG_REG1 (0x30) +#define ULPI_CONFIG_REG2 (0X31) +#define ULPI_CONFIG_REG (0x31) +#define ULPI_CONFIG_REG3 (0X32) +#define ULPI_CHG_DETECT_REG (0x34) +#define ULPI_PRE_EMPHASIS_MASK (3 << 4) +#define ULPI_DRV_AMPL_MASK (3 << 2) +#define ULPI_ONCLOCK (1 << 6) +#define ULPI_FUNC_SUSPENDM (1 << 6) +#define ULPI_IDPU (1 << 0) +#define ULPI_HOST_DISCONNECT (1 << 0) +#define ULPI_VBUS_VALID (1 << 1) +#define ULPI_SE1_GATE (1 << 2) +#define ULPI_SESS_END (1 << 3) +#define ULPI_ID_GND (1 << 4) #define ULPI_WAKEUP (1 << 31) #define ULPI_RUN (1 << 30) #define ULPI_WRITE (1 << 29) @@ -184,12 +252,17 @@ struct ept_queue_item { #define ULPI_DATA(n) ((n) & 255) #define ULPI_DATA_READ(n) (((n) >> 8) & 255) -#define ULPI_DEBUG_REG (0x15) -#define ULPI_SCRATCH_REG (0x16) +/* control charger detection by ULPI or externally */ +#define ULPI_EXTCHGCTRL_65NM (1 << 2) +#define ULPI_EXTCHGCTRL_180NM (1 << 3) -#define ULPI_FUNC_CTRL_CLR (0x06) -#define ULPI_FUNC_SUSPENDM (1 << 6) +/* charger detection power on control */ +#define ULPI_CHGDETON (1 << 1) +/* enable charger detection */ +#define ULPI_CHGDETEN (1 << 0) +#define ULPI_CHGTYPE_65NM (1 << 3) +#define ULPI_CHGTYPE_180NM (1 << 4) /* USB_PORTSC bits for determining port speed */ #define PORTSC_PSPD_FS (0 << 26) @@ -218,6 +291,30 @@ struct ept_queue_item { #define PORTSC_FPR (1 << 6) /* R/W - State normal => suspend */ #define PORTSC_SUSP (1 << 7) /* Read - Port in suspend state */ #define PORTSC_LS (3 << 10) /* Read - Port's Line status */ +#define PORTSC_PHCD (1 << 23) /* phy suspend mode */ +#define PORTSC_CCS (1 << 0) /* current connect status */ +#define PORTSC_PTS (3 << 30) +#define PORTSC_PTS_ULPI (2 << 30) +#define PORTSC_PTS_SERIAL (3 << 30) + +#define PORTSC_PORT_SPEED_FULL 0x00000000 +#define PORTSC_PORT_SPEED_LOW 0x04000000 +#define PORTSC_PORT_SPEED_HIGH 0x08000000 +#define PORTSC_PORT_SPEED_MASK 0x0c000000 + +#define SBUSCFG_AHBBRST_INCR4 0x01 +#define ULPI_USBINTR_ENABLE_FALLING_S 0x11 +#define ULPI_USBINTR_ENABLE_FALLING_C 0x12 +#define ULPI_USBINTR_STATUS 0x13 +#define ULPI_USBINTR_ENABLE_RASING_S 0x0E +#define ULPI_USBINTR_ENABLE_RASING_C 0x0F +#define ULPI_SESSION_END_RAISE (1 << 3) +#define ULPI_SESSION_END_FALL (1 << 3) +#define ULPI_SESSION_VALID_RAISE (1 << 2) +#define ULPI_SESSION_VALID_FALL (1 << 2) +#define ULPI_VBUS_VALID_RAISE (1 << 1) +#define ULPI_VBUS_VALID_FALL (1 << 1) + #define PORTSC_PHCD (1 << 23) /* phy suspend mode */ #define PORTSC_CCS (1 << 0) /* current connect status */ #define PORTSC_PTS (3 << 30) @@ -238,6 +335,9 @@ struct ept_queue_item { #define PORTSC_PTC_SE0_NAK (0x03 << 16) #define PORTSC_PTC_TST_PKT (0x04 << 16) +#define USBH (1 << 15) +#define USB_PHY (1 << 18) + #define PORTSC_PTS_MASK (3 << 30) #define PORTSC_PTS_ULPI (2 << 30) #define PORTSC_PTS_SERIAL (3 << 30) @@ -250,5 +350,9 @@ struct ept_queue_item { #define PORTSC_PHCD (1 << 23) /* phy suspend mode */ #define ULPI_DEBUG 0x15 +#define ULPI_CLOCK_SUSPENDM (1 << 3) #define ULPI_SUSPENDM (1 << 6) -#endif /* _USB_FUNCTION_MSM_HSUSB_HW_H */ +#define ULPI_CALIB_STS (1 << 7) +#define ULPI_CALIB_VAL(x) (x & 0x7C) + +#endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */ diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index f2a3f3ee..dc95c20e 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -21,11 +21,11 @@ #include #include #include - #include #include #include #include +#include #include #include @@ -33,6 +33,8 @@ #include #include "gadget_chips.h" +#include +#include /* * Kbuild is not very cooperative with respect to linking separately @@ -52,6 +54,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; +static struct wake_lock usb_rndis_idle_wake_lock; +static struct perf_lock usb_rndis_perf_lock; enum { USB_FUNCTION_UMS = 0, @@ -478,11 +482,14 @@ int android_switch_function(unsigned func) dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; #ifdef CONFIG_USB_GADGET_MSM_72K + /* avoid sending a disconnect switch event until after we disconnect */ msm_hsusb_request_reset(); #else /* force reenumeration */ if (dev->cdev && dev->cdev->gadget && dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) { + + /* avoid sending a disconnect switch event until after we disconnect */ usb_gadget_disconnect(dev->cdev->gadget); msleep(10); usb_gadget_connect(dev->cdev->gadget); @@ -500,6 +507,7 @@ void android_enable_function(struct usb_function *f, int enable) if (!!f->hidden != disable) { f->hidden = disable; + #ifdef CONFIG_USB_ANDROID_RNDIS if (!strcmp(f->name, "rndis")) { struct usb_function *func; @@ -565,6 +573,9 @@ static int __init android_probe(struct platform_device *pdev) printk(KERN_INFO "android_probe pdata: %p\n", pdata); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + if (pdata) { dev->products = pdata->products; dev->num_products = pdata->num_products; @@ -593,8 +604,26 @@ static int __init android_probe(struct platform_device *pdev) return usb_composite_register(&android_usb_driver); } +static int andr_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int andr_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static struct dev_pm_ops andr_dev_pm_ops = { + .runtime_suspend = andr_runtime_suspend, + .runtime_resume = andr_runtime_resume, +}; static struct platform_driver android_platform_driver = { - .driver = { .name = "android_usb", }, + .driver = { + .name = "android_usb", + .pm = &andr_dev_pm_ops}, .probe = android_probe, }; @@ -612,6 +641,8 @@ static int __init init(void) dev->product_id = PRODUCT_ID; _android_dev = dev; + wake_lock_init(&usb_rndis_idle_wake_lock, WAKE_LOCK_IDLE, "rndis_idle_lock"); + perf_lock_init(&usb_rndis_perf_lock, PERF_LOCK_HIGHEST, "rndis"); return platform_driver_register(&android_platform_driver); } module_init(init); diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index 39fc2f17..b9f58126 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -31,13 +31,11 @@ #include #include -#include #define BULK_BUFFER_SIZE 4096 /* number of tx requests to allocate */ #define TX_REQ_MAX 4 -#define RX_REQ_MAX 32 static const char shortname[] = "android_adb"; @@ -57,18 +55,11 @@ struct adb_dev { atomic_t open_excl; struct list_head tx_idle; - struct list_head rx_idle; - struct list_head rx_done; wait_queue_head_t read_wq; wait_queue_head_t write_wq; - - /* the request we're currently reading from */ - struct usb_request *read_req; - unsigned char *read_buf; - unsigned read_count; - - int maxsize; + struct usb_request *rx_req; + int rx_done; }; static struct usb_interface_descriptor adb_interface_desc = { @@ -125,22 +116,6 @@ static struct usb_descriptor_header *hs_adb_descs[] = { NULL, }; -/* string descriptors: */ - -static struct usb_string adb_string_defs[] = { - [0].s = "ADB", - { } /* end of list */ -}; - -static struct usb_gadget_strings adb_string_table = { - .language = 0x0409, /* en-us */ - .strings = adb_string_defs, -}; - -static struct usb_gadget_strings *adb_strings[] = { - &adb_string_table, - NULL, -}; /* temporary variable used between adb_open() and adb_gadget_bind() */ static struct adb_dev *_adb_dev; @@ -179,12 +154,16 @@ static void adb_request_free(struct usb_request *req, struct usb_ep *ep) static inline int _lock(atomic_t *excl) { + int ret = -1; + + preempt_disable(); if (atomic_inc_return(excl) == 1) { - return 0; - } else { + ret = 0; + } else atomic_dec(excl); - return -1; - } + + preempt_enable(); + return ret; } static inline void _unlock(atomic_t *excl) @@ -236,11 +215,9 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req) { struct adb_dev *dev = _adb_dev; - if (req->status != 0) { + dev->rx_done = 1; + if (req->status != 0) dev->error = 1; - req_put(dev, &dev->rx_idle, req); - } else - req_put(dev, &dev->rx_done, req); wake_up(&dev->read_wq); } @@ -275,13 +252,11 @@ static int __init create_bulk_endpoints(struct adb_dev *dev, dev->ep_out = ep; /* now allocate requests for our endpoints */ - for (i = 0; i < RX_REQ_MAX; i++) { - req = adb_request_new(dev->ep_out, 512); - if (!req) - goto fail; - req->complete = adb_complete_out; - req_put(dev, &dev->rx_idle, req); - } + req = adb_request_new(dev->ep_out, BULK_BUFFER_SIZE); + if (!req) + goto fail; + req->complete = adb_complete_out; + dev->rx_req = req; for (i = 0; i < TX_REQ_MAX; i++) { req = adb_request_new(dev->ep_in, BULK_BUFFER_SIZE); @@ -329,71 +304,41 @@ static ssize_t adb_read(struct file *fp, char __user *buf, r = -EIO; goto done; } - while (count > 0) { - if (dev->error) { - r = -EIO; - break; - } - /* if we have idle read requests, get them queued */ - while ((req = req_get(dev, &dev->rx_idle))) { requeue_req: - req->length = dev->maxsize?dev->maxsize:512; - ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); - if (ret < 0) { - printk(KERN_INFO "adb_read: failed to queue req (%d)\n", ret); - r = -EIO; - dev->error = 1; - req_put(dev, &dev->rx_idle, req); - goto done; - } - } - - /* if we have data pending, give it to userspace */ - if (dev->read_count > 0) { - xfer = (dev->read_count < count) ? dev->read_count : count; - - if (copy_to_user(buf, dev->read_buf, xfer)) { - r = -EFAULT; - break; - } - dev->read_buf += xfer; - dev->read_count -= xfer; - buf += xfer; - count -= xfer; - - /* if we've emptied the buffer, release the request */ - if (dev->read_count == 0) { - req_put(dev, &dev->rx_idle, dev->read_req); - dev->read_req = 0; - } - continue; - } - - /* wait for a request to complete */ - req = 0; - ret = wait_event_interruptible(dev->read_wq, - ((req = req_get(dev, &dev->rx_done)) || dev->error)); - - if (req != 0) { - /* if we got a 0-len one we need to put it back into - ** service. if we made it the current read req we'd - ** be stuck forever - */ - if (req->actual == 0) - goto requeue_req; - - dev->read_req = req; - dev->read_count = req->actual; - dev->read_buf = req->buf; - } - - if (ret < 0) { - r = ret; - break; - } + /* queue a request */ + req = dev->rx_req; + req->length = count; + dev->rx_done = 0; + ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); + if (ret < 0) { + DBG(cdev, "adb_read: failed to queue req %p (%d)\n", req, ret); + r = -EIO; + dev->error = 1; + goto done; + } else { + DBG(cdev, "rx %p queue\n", req); } + /* wait for a request to complete */ + ret = wait_event_interruptible(dev->read_wq, dev->rx_done); + if (ret < 0) { + dev->error = 1; + r = ret; + goto done; + } + if (!dev->error) { + /* If we got a 0-len packet, throw it back and try again. */ + if (req->actual == 0) + goto requeue_req; + + DBG(cdev, "rx %p %d\n", req, req->actual); + xfer = (req->actual < count) ? req->actual : count; + if (copy_to_user(buf, req->buf, xfer)) + r = -EFAULT; + } else + r = -EIO; + done: _unlock(&dev->read_excl); DBG(cdev, "adb_read returning %d\n", r); @@ -468,9 +413,25 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, static int adb_open(struct inode *ip, struct file *fp) { - printk(KERN_INFO "adb_open\n"); - if (_lock(&_adb_dev->open_excl)) + static unsigned long last_print; + static unsigned long count = 0; + + if (++count == 1) + last_print = jiffies; + else { + if (!time_before(jiffies, last_print + HZ/2)) + count = 0; + last_print = jiffies; + } + + if (_lock(&_adb_dev->open_excl)) { + cpu_relax(); return -EBUSY; + } + + if (count < 5) + printk(KERN_INFO "adb_open(%s)\n", current->comm); + fp->private_data = _adb_dev; @@ -482,7 +443,19 @@ static int adb_open(struct inode *ip, struct file *fp) static int adb_release(struct inode *ip, struct file *fp) { - printk(KERN_INFO "adb_release\n"); + static unsigned long last_print; + static unsigned long count = 0; + + if (++count == 1) + last_print = jiffies; + else { + if (!time_before(jiffies, last_print + HZ/2)) + count = 0; + last_print = jiffies; + } + + if (count < 5) + printk(KERN_INFO "adb_release\n"); _unlock(&_adb_dev->open_excl); return 0; } @@ -580,10 +553,7 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f) spin_lock_irq(&dev->lock); - while ((req = req_get(dev, &dev->rx_done))) - adb_request_free(req, dev->ep_out); - while ((req = req_get(dev, &dev->rx_idle))) - adb_request_free(req, dev->ep_out); + adb_request_free(dev->rx_req, dev->ep_out); while ((req = req_get(dev, &dev->tx_idle))) adb_request_free(req, dev->ep_in); @@ -603,7 +573,6 @@ static int adb_function_set_alt(struct usb_function *f, struct adb_dev *dev = func_to_dev(f); struct usb_composite_dev *cdev = f->config->cdev; int ret; - struct usb_request *req; DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt); ret = usb_ep_enable(dev->ep_in, @@ -620,17 +589,7 @@ static int adb_function_set_alt(struct usb_function *f, usb_ep_disable(dev->ep_in); return ret; } - if (cdev->gadget->speed == USB_SPEED_FULL) - dev->maxsize = 64; - else - dev->maxsize = 512; - printk(KERN_INFO "%s: maxsize = %d\n", __func__, dev->maxsize); - - /* retire any completed rx requests from previous session */ - while ((req = req_get(dev, &dev->rx_done))) - req_put(dev, &dev->rx_idle, req); - - dev->online = !dev->function.hidden; + dev->online = 1; /* readers may be blocked waiting for us to go online */ wake_up(&dev->read_wq); @@ -645,7 +604,6 @@ static void adb_function_disable(struct usb_function *f) DBG(cdev, "adb_function_disable\n"); dev->online = 0; dev->error = 1; - dev->maxsize = 0; usb_ep_disable(dev->ep_in); usb_ep_disable(dev->ep_out); @@ -676,27 +634,18 @@ static int adb_bind_config(struct usb_configuration *c) atomic_set(&dev->write_excl, 0); INIT_LIST_HEAD(&dev->tx_idle); - INIT_LIST_HEAD(&dev->rx_idle); - INIT_LIST_HEAD(&dev->rx_done); - ret = usb_string_id(c->cdev); - if (ret < 0) - return ret; - adb_string_defs[0].id = ret; - adb_interface_desc.iInterface = ret; dev->cdev = c->cdev; dev->function.name = "adb"; - dev->function.strings = adb_strings; dev->function.descriptors = fs_adb_descs; dev->function.hs_descriptors = hs_adb_descs; dev->function.bind = adb_function_bind; dev->function.unbind = adb_function_unbind; dev->function.set_alt = adb_function_set_alt; dev->function.disable = adb_function_disable; - dev->maxsize = 512; - if (board_mfg_mode() != 2) - dev->function.hidden = 1; + /* start disabled */ +// dev->function.disabled = 1; /* _adb_dev must be set before calling usb_gadget_register_driver */ _adb_dev = dev; diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 689093b2..e7abad59 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -4,6 +4,8 @@ * Copyright (C) 2003-2005,2008 David Brownell * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger * Copyright (C) 2008 Nokia Corporation + * Copyright (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +24,7 @@ /* #define VERBOSE_DEBUG */ +#include #include #include #include @@ -84,6 +87,8 @@ struct f_rndis { struct gether port; u8 ctrl_id, data_id; u8 ethaddr[ETH_ALEN]; + u32 vendorID; + const char *manufacturer; int config; struct rndis_ep_descs fs; @@ -95,6 +100,8 @@ struct f_rndis { atomic_t notify_count; }; +static char manufacturer [10] = "HTC"; +static u32 vendorID = 0x0bb4; static inline struct f_rndis *func_to_rndis(struct usb_function *f) { return container_of(f, struct f_rndis, port.func); @@ -412,8 +419,7 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) */ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) | USB_CDC_SEND_ENCAPSULATED_COMMAND: - if (w_length > req->length || w_value - || w_index != rndis->ctrl_id) + if (w_value || w_index != rndis->ctrl_id) goto invalid; /* read the request; process it later */ value = w_length; @@ -820,6 +826,8 @@ int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) goto fail; memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); + rndis->vendorID = vendorID; + rndis->manufacturer = manufacturer; /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c index be1fd75f..4986e03f 100644 --- a/drivers/usb/gadget/msm72k_udc.c +++ b/drivers/usb/gadget/msm72k_udc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,10 @@ #ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC #include #endif +#ifdef CONFIG_CABLE_DETECT_ACCESSORY +#include +#endif +#include static const char driver_name[] = "msm72k_udc"; @@ -63,7 +68,6 @@ static const char driver_name[] = "msm72k_udc"; #define SETUP_BUF_SIZE 4096 -typedef void (*completion_func)(struct usb_ep *ep, struct usb_request *req); static const char *const ep_name[] = { "ep0out", "ep1out", "ep2out", "ep3out", @@ -81,25 +85,41 @@ 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", }; -#define DOCK_STATE_UNDOCKED 0 -#define DOCK_STATE_DESK (1 << 0) -#define DOCK_STATE_CAR (1 << 1) +#define DOCK_STATE_UNDOCKED 0 +#define DOCK_STATE_DESK (1 << 0) +#define DOCK_STATE_CAR (1 << 1) +#define DOCK_STATE_USB_HEADSET (1 << 2) +#define DOCK_STATE_MHL (1 << 3) +#define DOCK_STATE_CREDLE (1 << 4) + +#define DOCK_DET_DELAY HZ/4 #endif +#include +#include + +static struct wake_lock vbus_idle_wake_lock; +static struct perf_lock usb_perf_lock; + struct msm_request { struct usb_request req; /* saved copy of req.complete */ - completion_func gadget_complete; + void (*gadget_complete)(struct usb_ep *ep, + struct usb_request *req); + struct usb_info *ui; struct msm_request *next; @@ -138,10 +158,16 @@ struct msm_endpoint { }; static void usb_do_work(struct work_struct *w); +static void do_usb_hub_disable(struct work_struct *w); static void check_charger(struct work_struct *w); #ifdef CONFIG_USB_ACCESSORY_DETECT static void accessory_detect_work(struct work_struct *w); #endif +#ifdef CONFIG_DOCK_ACCESSORY_DETECT +static void dock_isr_work(struct work_struct *w); +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); @@ -154,13 +180,7 @@ extern void android_set_serialno(char *serialno); #define USB_FLAG_VBUS_ONLINE 0x0002 #define USB_FLAG_VBUS_OFFLINE 0x0004 #define USB_FLAG_RESET 0x0008 - -enum usb_connect_type { - CONNECT_TYPE_NONE = 0, - CONNECT_TYPE_USB, - CONNECT_TYPE_AC, - CONNECT_TYPE_UNKNOWN, -}; +#define USB_FLAG_CONFIGURED 0x0020 struct usb_info { /* lock for register/queue/device state changes */ @@ -176,8 +196,8 @@ struct usb_info { unsigned state; unsigned flags; - unsigned online:1; - unsigned running:1; + atomic_t online; + atomic_t running; struct dma_pool *pool; @@ -200,8 +220,17 @@ 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); + void (*change_phy_voltage)(int); + int (*ldo_init) (int init); + int (*ldo_enable) (int enable); + void (*usb_mhl_switch)(bool); /* for notification when USB is connected or disconnected */ + int connect_type_ready; void (*usb_connected)(int); struct workqueue_struct *usb_wq; @@ -209,11 +238,13 @@ struct usb_info { struct delayed_work chg_work; struct work_struct detect_work; struct work_struct notifier_work; + struct work_struct usb_hub_work; unsigned phy_status; unsigned phy_fail_count; struct usb_gadget gadget; struct usb_gadget_driver *driver; + struct switch_dev sdev; #define ep0out ept[0] #define ep0in ept[16] @@ -223,22 +254,35 @@ struct usb_info { struct clk *pclk; struct clk *otgclk; struct clk *ebi1clk; + struct clk *pclk_src; - unsigned int ep0_dir; - u16 test_mode; + atomic_t ep0_dir; + atomic_t test_mode; - u8 remote_wakeup; + atomic_t remote_wakeup; enum usb_connect_type connect_type; u8 in_lpm; /* for accessory detection */ + bool dock_detect; u8 accessory_detect; u8 mfg_usb_carkit_enable; int idpin_irq; int usb_id_pin_gpio; + + int dockpin_irq; + int dock_pin_gpio; + uint8_t dock_pin_state; + struct delayed_work dock_work_isr; + struct delayed_work dock_work; + void (*config_usb_id_gpios)(bool output_enable); - /* 0: none, 1: carkit, 2: usb headset */ + /* 0: none, 1: carkit, 2: usb headset, 4: mhl */ u8 accessory_type; + struct timer_list ac_detect_timer; + int ac_detect_count; + int ac_9v_gpio; + char *pclk_src_name; }; static const struct usb_ep_ops msm72k_ep_ops; @@ -257,7 +301,8 @@ static void send_usb_connect_notify(struct work_struct *w) if (!ui) return; - printk(KERN_INFO "usb: send connect type %d\n", ui->connect_type); + ui->connect_type_ready = 1; + USB_INFO("send connect type %d\n", ui->connect_type); mutex_lock(¬ify_sem); list_for_each_entry(notifier, &g_lh_usb_notifier_list, @@ -286,6 +331,16 @@ int usb_register_notifier(struct t_usb_status_notifier *notifier) return 0; } +static ssize_t print_switch_name(struct switch_dev *sdev, char *buf) +{ + return sprintf(buf, "%s\n", driver_name); +} + +static ssize_t print_switch_state(struct switch_dev *sdev, char *buf) +{ + return sprintf(buf, "%s\n", sdev->state ? "online" : "offline"); +} + static int usb_ep_get_stall(struct msm_endpoint *ept) { unsigned int n; @@ -310,7 +365,7 @@ static unsigned ulpi_read(struct usb_info *ui, unsigned reg) while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ; if (timeout == 0) { - ERROR("ulpi_read: timeout %08x\n", readl(USB_ULPI_VIEWPORT)); + USB_ERR("ulpi_read: timeout %08x\n", readl(USB_ULPI_VIEWPORT)); return 0xffffffff; } return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT)); @@ -326,10 +381,10 @@ static int ulpi_write(struct usb_info *ui, unsigned val, unsigned reg) 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"); + USB_ERR("ulpi_write: timeout\n"); return -1; } @@ -344,7 +399,7 @@ static void ulpi_init(struct usb_info *ui) return; while (seq[0] >= 0) { - INFO("ulpi: write 0x%02x to 0x%02x\n", seq[0], seq[1]); + USB_INFO("ulpi: write 0x%02x to 0x%02x\n", seq[0], seq[1]); ulpi_write(ui, seq[0], seq[1]); seq += 2; } @@ -386,6 +441,7 @@ static void config_ept(struct msm_endpoint *ept) ept->head->config = cfg; ept->head->next = TERMINATE; + #if 0 if (ept->ep.maxpacket) INFO("ept #%d %s max:%d head:%p bit:%d\n", @@ -471,7 +527,7 @@ static void usb_ept_enable(struct msm_endpoint *ept, int yes, n |= CTRL_TXT_ISOCH; break; default: - pr_err("%s: unsupported ep_type %d for %s\n", + USB_ERR("%s: unsupported ep_type %d for %s\n", __func__, ep_type, ept->ep.name); break; } @@ -495,7 +551,7 @@ static void usb_ept_enable(struct msm_endpoint *ept, int yes, n |= CTRL_RXT_ISOCH; break; default: - pr_err("%s: unsupported ep_type %d for %s\n", + USB_ERR("%s: unsupported ep_type %d for %s\n", __func__, ep_type, ept->ep.name); break; } @@ -513,21 +569,55 @@ static void usb_ept_start(struct msm_endpoint *ept) { struct usb_info *ui = ept->ui; struct msm_request *req = ept->req; + int i, cnt; + unsigned n = 1 << ept->bit; BUG_ON(req->live); - /* link the hw queue head to the request's transaction item */ - ept->head->next = req->item_dma; - ept->head->info = 0; - - /* start the endpoint */ - writel(1 << ept->bit, USB_ENDPTPRIME); - - /* mark this chain of requests as live */ while (req) { req->live = 1; + /* prepare the transaction descriptor item for the hardware */ + req->item->info = + INFO_BYTES(req->req.length) | INFO_IOC | INFO_ACTIVE; + req->item->page0 = req->dma; + req->item->page1 = (req->dma + 0x1000) & 0xfffff000; + req->item->page2 = (req->dma + 0x2000) & 0xfffff000; + req->item->page3 = (req->dma + 0x3000) & 0xfffff000; + + if (req->next == NULL) { + req->item->next = TERMINATE; + break; + } + req->item->next = req->next->item_dma; req = req->next; } + /* link the hw queue head to the request's transaction item */ + ept->head->next = ept->req->item_dma; + ept->head->info = 0; + + /* during high throughput testing it is observed that + * ept stat bit is not set even thoguh all the data + * structures are updated properly and ept prime bit + * is set. To workaround the issue, try to check if + * ept stat bit otherwise try to re-prime the ept + */ + for (i = 0; i < 5; i++) { + writel(n, USB_ENDPTPRIME); + for (cnt = 0; cnt < 3000; cnt++) { + if (!(readl(USB_ENDPTPRIME) & n) && + (readl(USB_ENDPTSTAT) & n)) + return; + udelay(1); + } + } + + if ((readl(USB_ENDPTPRIME) & n) && !(readl(USB_ENDPTSTAT) & n)) { + USB_ERR("Unable to prime the ept%d%s\n", + ept->num, + ept->flags & EPT_FLAG_IN ? "in" : "out"); + } + + return; } int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req) @@ -536,7 +626,6 @@ int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req) struct msm_request *req = to_msm_request(_req); struct msm_request *last; struct usb_info *ui = ept->ui; - struct ept_queue_item *item = req->item; unsigned length = req->req.length; if (length > 0x4000) @@ -547,14 +636,14 @@ int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req) if (req->busy) { req->req.status = -EBUSY; spin_unlock_irqrestore(&ui->lock, flags); - INFO("usb_ept_queue_xfer() tried to queue busy request\n"); + USB_INFO("usb_ept_queue_xfer() tried to queue busy request\n"); return -EBUSY; } - if (!ui->online && (ept->num != 0)) { + if (!atomic_read(&ui->online) && (ept->num != 0)) { req->req.status = -ESHUTDOWN; spin_unlock_irqrestore(&ui->lock, flags); - INFO("usb_ept_queue_xfer() called while offline\n"); + USB_INFO("usb_ept_queue_xfer() called while offline\n"); return -ESHUTDOWN; } @@ -567,14 +656,6 @@ int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req) (ept->flags & EPT_FLAG_IN) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - /* prepare the transaction descriptor item for the hardware */ - item->next = TERMINATE; - item->info = INFO_BYTES(length) | INFO_IOC | INFO_ACTIVE; - item->page0 = req->dma; - item->page1 = (req->dma + 0x1000) & 0xfffff000; - item->page2 = (req->dma + 0x2000) & 0xfffff000; - item->page3 = (req->dma + 0x3000) & 0xfffff000; - /* Add the new request to the end of the queue */ last = ept->last; if (last) { @@ -587,8 +668,6 @@ int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req) /* only modify the hw transaction next pointer if * that request is not live */ - if (!last->live) - last->item->next = req->item_dma; } else { /* queue was empty -- kick the hardware */ ept->req = req; @@ -609,7 +688,7 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req) struct usb_info *ui = ept->ui; req->complete = r->gadget_complete; - r->gadget_complete = NULL; + r->gadget_complete = 0; if (req->complete) req->complete(&ui->ep0in.ep, req); } @@ -621,22 +700,16 @@ static void ep0_queue_ack_complete(struct usb_ep *ep, struct msm_endpoint *ept = to_msm_endpoint(ep); struct usb_info *ui = ept->ui; struct usb_request *req = ui->setup_req; - completion_func gadget_complete = r->gadget_complete; - - if (gadget_complete) { - r->gadget_complete = NULL; - gadget_complete(ep, req); - } /* queue up the receive of the ACK response from the host */ if (_req->status == 0 && _req->actual == _req->length) { req->length = 0; - if (ui->ep0_dir == USB_DIR_IN) + if (atomic_read(&ui->ep0_dir) == USB_DIR_IN) usb_ept_queue_xfer(&ui->ep0out, req); else usb_ept_queue_xfer(&ui->ep0in, req); _req->complete = r->gadget_complete; - r->gadget_complete = NULL; + r->gadget_complete = 0; if (_req->complete) _req->complete(&ui->ep0in.ep, _req); } else @@ -648,31 +721,32 @@ static void ep0_setup_ack_complete(struct usb_ep *ep, struct usb_request *req) struct msm_endpoint *ept = to_msm_endpoint(ep); struct usb_info *ui = ept->ui; unsigned int temp; + int test_mode = atomic_read(&ui->test_mode); - if (!ui->test_mode) + if (!test_mode) return; - switch (ui->test_mode) { + switch (test_mode) { case J_TEST: - pr_info("usb electrical test mode: (J)\n"); + USB_INFO("usb electrical test mode: (J)\n"); temp = readl(USB_PORTSC) & (~PORTSC_PTC); writel(temp | PORTSC_PTC_J_STATE, USB_PORTSC); break; case K_TEST: - pr_info("usb electrical test mode: (K)\n"); + USB_INFO("usb electrical test mode: (K)\n"); temp = readl(USB_PORTSC) & (~PORTSC_PTC); writel(temp | PORTSC_PTC_K_STATE, USB_PORTSC); break; case SE0_NAK_TEST: - pr_info("usb electrical test mode: (SE0-NAK)\n"); + USB_INFO("usb electrical test mode: (SE0-NAK)\n"); temp = readl(USB_PORTSC) & (~PORTSC_PTC); writel(temp | PORTSC_PTC_SE0_NAK, USB_PORTSC); break; case TST_PKT_TEST: - pr_info("usb electrical test mode: (TEST_PKT)\n"); + USB_INFO("usb electrical test mode: (TEST_PKT)\n"); temp = readl(USB_PORTSC) & (~PORTSC_PTC); writel(temp | PORTSC_PTC_TST_PKT, USB_PORTSC); break; @@ -700,7 +774,7 @@ static void ep0_setup_send(struct usb_info *ui, unsigned length) req->length = length; req->complete = ep0_queue_ack_complete; - r->gadget_complete = NULL; + r->gadget_complete = 0; usb_ept_queue_xfer(ept, req); } @@ -714,9 +788,9 @@ static void handle_setup(struct usb_info *ui) writel(EPT_RX(0), USB_ENDPTSETUPSTAT); if (ctl.bRequestType & USB_DIR_IN) - ui->ep0_dir = USB_DIR_IN; + atomic_set(&ui->ep0_dir, USB_DIR_IN); else - ui->ep0_dir = USB_DIR_OUT; + atomic_set(&ui->ep0_dir, USB_DIR_OUT); /* any pending ep0 transactions must be canceled */ flush_endpoint(&ui->ep0out); @@ -757,9 +831,8 @@ static void handle_setup(struct usb_info *ui) { u16 temp = 0; - temp = 1 << USB_DEVICE_SELF_POWERED; - temp |= (ui->remote_wakeup << - USB_DEVICE_REMOTE_WAKEUP); + temp |= (atomic_read(&ui->remote_wakeup) + << USB_DEVICE_REMOTE_WAKEUP); memcpy(req->buf, &temp, 2); break; } @@ -797,9 +870,11 @@ static void handle_setup(struct usb_info *ui) } } if (ctl.bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD)) { - if (ctl.bRequest == USB_REQ_SET_CONFIGURATION) - ui->online = !!ctl.wValue; - else if (ctl.bRequest == USB_REQ_SET_ADDRESS) { + if (ctl.bRequest == USB_REQ_SET_CONFIGURATION) { + atomic_set(&ui->online, !!ctl.wValue); + ui->flags |= USB_FLAG_CONFIGURED; + queue_work(ui->usb_wq, &ui->work); + } else if (ctl.bRequest == USB_REQ_SET_ADDRESS) { /* write address delayed (will take effect ** after the next IN txn) */ @@ -812,18 +887,22 @@ static void handle_setup(struct usb_info *ui) case J_TEST: case K_TEST: case SE0_NAK_TEST: + if (!atomic_read(&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; + atomic_set(&ui->test_mode, ctl.wIndex); goto ack; } goto stall; case USB_DEVICE_REMOTE_WAKEUP: - ui->remote_wakeup = 1; + atomic_set(&ui->remote_wakeup, 1); goto ack; } } else if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) && (ctl.wValue == USB_DEVICE_REMOTE_WAKEUP)) { - ui->remote_wakeup = 0; + atomic_set(&ui->remote_wakeup, 0); goto ack; } } @@ -860,8 +939,6 @@ static void handle_endpoint(struct usb_info *ui, unsigned bit) /* expire all requests that are no longer active */ spin_lock_irqsave(&ui->lock, flags); while ((req = ept->req)) { - info = req->item->info; - /* if we've processed all live requests, time to * restart the hardware on the next non-live request */ @@ -870,6 +947,9 @@ static void handle_endpoint(struct usb_info *ui, unsigned bit) break; } + /* clean speculative fetches on req->item->info */ + dma_coherent_post_ops(); + info = req->item->info; /* if the transaction is still in-flight, stop here */ if (info & INFO_ACTIVE) break; @@ -887,7 +967,7 @@ static void handle_endpoint(struct usb_info *ui, unsigned bit) /* XXX pass on more specific error code */ req->req.status = -EIO; req->req.actual = 0; - INFO("msm72k_udc: ept %d %s error. info=%08x\n", + USB_INFO("msm72k_udc: ept %d %s error. info=%08x\n", ept->num, (ept->flags & EPT_FLAG_IN) ? "in" : "out", info); @@ -900,8 +980,7 @@ static void handle_endpoint(struct usb_info *ui, unsigned bit) req->live = 0; if (req->dead) do_free_req(ui, req); - - if (req->req.complete) { + else if (req->req.complete) { spin_unlock_irqrestore(&ui->lock, flags); req->req.complete(&ept->ep, &req->req); spin_lock_irqsave(&ui->lock, flags); @@ -942,7 +1021,7 @@ static void flush_endpoint_hw(struct usb_info *ui, unsigned bits) } err: - pr_warning("%s: Could not complete flush! NOT GOOD! " + USB_WARNING("%s: Could not complete flush! NOT GOOD! " "stat: %x unflushed: %x bits: %x\n", __func__, stat, unflushed, bits); done: @@ -952,7 +1031,7 @@ done: static void flush_endpoint_sw(struct msm_endpoint *ept) { struct usb_info *ui = ept->ui; - struct msm_request *req; + struct msm_request *req, *next_req = NULL; unsigned long flags; /* inactive endpoints have nothing to do here */ @@ -963,6 +1042,9 @@ static void flush_endpoint_sw(struct msm_endpoint *ept) ept->head->info = 0; ept->head->next = TERMINATE; + /* flush buffers before priming ept */ + dma_coherent_pre_ops(); + /* cancel any pending requests */ spin_lock_irqsave(&ui->lock, flags); req = ept->req; @@ -973,6 +1055,13 @@ static void flush_endpoint_sw(struct msm_endpoint *ept) req->live = 0; req->req.status = -ECONNRESET; req->req.actual = 0; + + /* + * Gadget driver may free the request in completion + * handler. So keep a copy of next req pointer + * before calling completion handler. + */ + next_req = req->next; if (req->req.complete) { spin_unlock_irqrestore(&ui->lock, flags); req->req.complete(&ept->ep, &req->req); @@ -980,7 +1069,7 @@ static void flush_endpoint_sw(struct msm_endpoint *ept) } if (req->dead) do_free_req(ui, req); - req = req->next; + req = next_req; } spin_unlock_irqrestore(&ui->lock, flags); } @@ -991,78 +1080,79 @@ static void flush_endpoint(struct msm_endpoint *ept) flush_endpoint_sw(ept); } -static void flush_all_endpoints(struct usb_info *ui) +static void handle_notify_offline(struct usb_info *ui) { - unsigned n; - - flush_endpoint_hw(ui, 0xffffffff); - - for (n = 0; n < 32; n++) - flush_endpoint_sw(ui->ept + n); + if (ui->driver) { + USB_INFO("%s: notify offline\n", __func__); + ui->driver->disconnect(&ui->gadget); + } + /* cancel pending ep0 transactions */ + flush_endpoint(&ui->ep0out); + flush_endpoint(&ui->ep0in); } - static irqreturn_t usb_interrupt(int irq, void *data) { struct usb_info *ui = data; unsigned n; + unsigned long flags; n = readl(USB_USBSTS); writel(n, USB_USBSTS); /* somehow we got an IRQ while in the reset sequence: ignore it */ - if (ui->running == 0) + if (!atomic_read(&ui->running)) return IRQ_HANDLED; if (n & STS_PCI) { switch (readl(USB_PORTSC) & PORTSC_PSPD_MASK) { case PORTSC_PSPD_FS: - INFO("usb: portchange USB_SPEED_FULL\n"); + USB_INFO("portchange USB_SPEED_FULL\n"); + spin_lock_irqsave(&ui->lock, flags); ui->gadget.speed = USB_SPEED_FULL; + spin_unlock_irqrestore(&ui->lock, flags); break; case PORTSC_PSPD_LS: - INFO("usb: portchange USB_SPEED_LOW\n"); + USB_INFO("portchange USB_SPEED_LOW\n"); + spin_lock_irqsave(&ui->lock, flags); ui->gadget.speed = USB_SPEED_LOW; + spin_unlock_irqrestore(&ui->lock, flags); break; case PORTSC_PSPD_HS: - INFO("usb: portchange USB_SPEED_HIGH\n"); + USB_INFO("portchange USB_SPEED_HIGH\n"); + spin_lock_irqsave(&ui->lock, flags); ui->gadget.speed = USB_SPEED_HIGH; + spin_unlock_irqrestore(&ui->lock, flags); break; } } if (n & STS_URI) { - INFO("usb: reset\n"); + USB_INFO("reset\n"); writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT); writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE); writel(0xffffffff, USB_ENDPTFLUSH); writel(0, USB_ENDPTCTRL(1)); - if (ui->online != 0) { + if (atomic_read(&ui->online)) { /* marking us offline will cause ept queue attempts ** to fail */ - ui->online = 0; + atomic_set(&ui->online, 0); - flush_all_endpoints(ui); - - /* XXX: we can't seem to detect going offline, - * XXX: so deconfigure on reset for the time being - */ - if (ui->driver) { - printk(KERN_INFO "usb: notify offline\n"); - ui->driver->disconnect(&ui->gadget); - } + handle_notify_offline(ui); } if (ui->connect_type != CONNECT_TYPE_USB) { ui->connect_type = CONNECT_TYPE_USB; queue_work(ui->usb_wq, &ui->notifier_work); + ui->ac_detect_count = 0; + del_timer_sync(&ui->ac_detect_timer); } } if (n & STS_SLI) - INFO("usb: suspend\n"); + USB_INFO("suspend\n"); if (n & STS_UI) { n = readl(USB_ENDPTSETUPSTAT); @@ -1080,6 +1170,14 @@ static irqreturn_t usb_interrupt(int irq, void *data) return IRQ_HANDLED; } +int usb_is_connect_type_ready(void) +{ + if (!the_usb_info) + return 0; + return the_usb_info->connect_type_ready; +} +EXPORT_SYMBOL(usb_is_connect_type_ready); + int usb_get_connect_type(void) { if (!the_usb_info) @@ -1134,7 +1232,7 @@ static ssize_t store_usb_function_switch(struct device *dev, return 0; } -static DEVICE_ATTR(usb_function_switch, 0666, +static DEVICE_ATTR(usb_function_switch, 0664, show_usb_function_switch, store_usb_function_switch); static ssize_t show_usb_serial_number(struct device *dev, @@ -1151,12 +1249,12 @@ static ssize_t store_usb_serial_number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct msm_hsusb_platform_data *pdata = dev->platform_data; + char *serialno = "000000000000"; if (buf[0] == '0' || buf[0] == '1') { memset(mfg_df_serialno, 0x0, sizeof(mfg_df_serialno)); if (buf[0] == '0') { - strncpy(mfg_df_serialno, "000000000000", - strlen("000000000000")); + strncpy(mfg_df_serialno, serialno, strlen(serialno)); use_mfg_serialno = 1; android_set_serialno(mfg_df_serialno); } else { @@ -1207,7 +1305,7 @@ static ssize_t store_dummy_usb_serial_number(struct device *dev, if (buf[loop_i] == 0x0A) /* Line Feed */ continue; else { - printk(KERN_WARNING "%s(): get invaild char (0x%2.2X)\n", + USB_WARNING("%s(): get invaild char (0x%2.2X)\n", __func__, buf[loop_i]); return -EINVAL; } @@ -1226,9 +1324,37 @@ static ssize_t store_dummy_usb_serial_number(struct device *dev, static DEVICE_ATTR(dummy_usb_serial_number, 0644, show_dummy_usb_serial_number, store_dummy_usb_serial_number); +static void usb_lpm_enter(struct usb_info *ui); +static void usb_lpm_exit(struct usb_info *ui); + static ssize_t show_USB_ID_status(struct device *dev, struct device_attribute *attr, char *buf) +{ + int value = 1; + unsigned length; +#if defined(CONFIG_CABLE_DETECT_ACCESSORY) + value = cable_get_usb_id_level(); +#else + struct usb_info *ui = the_usb_info; + + if (!ui) + return 0; + if (ui->usb_id_pin_gpio != 0) { + value = gpio_get_value(ui->usb_id_pin_gpio); + USB_INFO("id pin status %d\n", value); + } +#endif + length = sprintf(buf, "%d", value); + return length; +} + +static DEVICE_ATTR(USB_ID_status, 0444, + show_USB_ID_status, NULL); + +static ssize_t show_usb_car_kit_enable(struct device *dev, + struct device_attribute *attr, + char *buf) { struct usb_info *ui = the_usb_info; int value = 1; @@ -1236,16 +1362,16 @@ static ssize_t show_USB_ID_status(struct device *dev, if (!ui) return 0; - if (ui->usb_id_pin_gpio != 0) { - value = gpio_get_value(ui->usb_id_pin_gpio); - printk(KERN_INFO "usb: id pin status %d\n", value); + if (ui->accessory_detect == 0) { + value = 0; } + USB_INFO("USB_car_kit_enable %d\n", ui->accessory_detect); length = sprintf(buf, "%d", value); return length; } -static DEVICE_ATTR(USB_ID_status, 0444, - show_USB_ID_status, NULL); +static DEVICE_ATTR(usb_car_kit_enable, 0444, + show_usb_car_kit_enable, NULL);/*for kar kit AP check if car kit enable*/ static ssize_t show_usb_phy_setting(struct device *dev, struct device_attribute *attr, char *buf) @@ -1273,20 +1399,20 @@ static ssize_t store_usb_phy_setting(struct device *dev, unsigned value; int i; - printk(KERN_INFO "%s\n", buf); + USB_INFO("%s\n", buf); for (i = 0; i < 2; i++) token[i] = strsep((char **)&buf, " "); reg = simple_strtoul(token[0], NULL, 16); value = simple_strtoul(token[1], NULL, 16); - printk(KERN_INFO "Set 0x%x = 0x%x\n", reg, value); + USB_INFO("Set 0x%x = 0x%x\n", reg, value); ulpi_write(ui, value, reg); return 0; } -static DEVICE_ATTR(usb_phy_setting, 0666, +static DEVICE_ATTR(usb_phy_setting, 0664, show_usb_phy_setting, store_usb_phy_setting); #ifdef CONFIG_USB_ACCESSORY_DETECT @@ -1297,8 +1423,7 @@ static ssize_t show_mfg_carkit_enable(struct device *dev, struct usb_info *ui = the_usb_info; length = sprintf(buf, "%d", ui->mfg_usb_carkit_enable); - printk(KERN_INFO "%s: %d\n", __func__, - ui->mfg_usb_carkit_enable); + USB_INFO("%s: %d\n", __func__, ui->mfg_usb_carkit_enable); return length; } @@ -1310,29 +1435,33 @@ static ssize_t store_mfg_carkit_enable(struct device *dev, unsigned char uc; if (buf[0] != '0' && buf[0] != '1') { - printk(KERN_ERR "Can't enable/disable carkit\n"); + USB_ERR("Can't enable/disable carkit\n"); return -EINVAL; } uc = buf[0] - '0'; - printk(KERN_INFO "%s: %d\n", __func__, uc); + USB_INFO("%s: %d\n", __func__, uc); ui->mfg_usb_carkit_enable = uc; if (uc == 1 && ui->accessory_type == 1 && board_mfg_mode() == 1) { switch_set_state(&dock_switch, DOCK_STATE_CAR); - printk(KERN_INFO "carkit: set state %d\n", DOCK_STATE_CAR); + USB_INFO("carkit: set state %d\n", DOCK_STATE_CAR); } return count; } 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"); } @@ -1362,52 +1491,76 @@ static void usb_prepare(struct usb_info *ui) ui->usb_wq = create_singlethread_workqueue("msm_hsusb"); if (ui->usb_wq == 0) { - printk(KERN_ERR "usb: fail to create workqueue\n"); + USB_ERR("fail to create workqueue\n"); return; } INIT_WORK(&ui->work, usb_do_work); #ifdef CONFIG_USB_ACCESSORY_DETECT INIT_WORK(&ui->detect_work, accessory_detect_work); #endif +#ifdef CONFIG_DOCK_ACCESSORY_DETECT + if (ui->dock_detect) { + INIT_DELAYED_WORK(&ui->dock_work_isr, dock_isr_work); + INIT_DELAYED_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); + if (ui->usb_hub_enable) + INIT_WORK(&ui->usb_hub_work, do_usb_hub_disable); + ret = device_create_file(&ui->pdev->dev, &dev_attr_usb_cable_connect); if (ret != 0) - printk(KERN_WARNING "dev_attr_usb_cable_connect failed\n"); + USB_WARNING("dev_attr_usb_cable_connect failed\n"); ret = device_create_file(&ui->pdev->dev, &dev_attr_usb_function_switch); if (ret != 0) - printk(KERN_WARNING "dev_attr_usb_function_switch failed\n"); + USB_WARNING("dev_attr_usb_function_switch failed\n"); ret = device_create_file(&ui->pdev->dev, &dev_attr_usb_serial_number); if (ret != 0) - printk(KERN_WARNING "dev_attr_usb_serial_number failed\n"); + USB_WARNING("dev_attr_usb_serial_number failed\n"); ret = device_create_file(&ui->pdev->dev, &dev_attr_dummy_usb_serial_number); if (ret != 0) - printk(KERN_WARNING "dev_attr_dummy_usb_serial_number failed\n"); + USB_WARNING("dev_attr_dummy_usb_serial_number failed\n"); ret = device_create_file(&ui->pdev->dev, &dev_attr_USB_ID_status); if (ret != 0) - printk(KERN_WARNING "dev_attr_USB_ID_status failed\n"); + USB_WARNING("dev_attr_USB_ID_status failed\n"); ret = device_create_file(&ui->pdev->dev, &dev_attr_usb_phy_setting); if (ret != 0) - printk(KERN_WARNING "dev_attr_usb_phy_setting failed\n"); + USB_WARNING("dev_attr_usb_phy_setting failed\n"); #ifdef CONFIG_USB_ACCESSORY_DETECT ret = device_create_file(&ui->pdev->dev, &dev_attr_usb_mfg_carkit_enable); if (ret != 0) - printk(KERN_WARNING "dev_attr_usb_mfg_carkit_enable failed\n"); + USB_WARNING("dev_attr_usb_mfg_carkit_enable failed\n"); #endif + ret = device_create_file(&ui->pdev->dev, + &dev_attr_usb_car_kit_enable);/*for kar kit AP check if car kit enable*/ + if (ret != 0) + USB_WARNING("dev_attr_usb_car_kit_enable failed\n"); + + ui->sdev.name = driver_name; + ui->sdev.print_name = print_switch_name; + ui->sdev.print_state = print_switch_state; + + ret = switch_dev_register(&ui->sdev); + if (ret != 0) + USB_WARNING("switch class can't be registered\n"); + } static int usb_wakeup_phy(struct usb_info *ui) @@ -1423,7 +1576,7 @@ static int usb_wakeup_phy(struct usb_info *ui) } if ((readl(USB_PORTSC) & PORTSC_PHCD)) { - pr_err("%s: cannot clear phcd bit\n", __func__); + USB_ERR("%s: cannot clear phcd bit\n", __func__); return -1; } @@ -1432,7 +1585,7 @@ static int usb_wakeup_phy(struct usb_info *ui) static void usb_suspend_phy(struct usb_info *ui) { - printk(KERN_INFO "%s\n", __func__); + USB_INFO("%s\n", __func__); #ifdef CONFIG_ARCH_MSM7X00A /* disable unused interrupt */ ulpi_write(ui, 0x01, 0x0d); @@ -1459,18 +1612,15 @@ static void usb_suspend_phy(struct usb_info *ui) writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC); mdelay(1); if (!(readl(USB_PORTSC) & PORTSC_PHCD)) - printk(KERN_INFO "%s: unable to set lpm\n", __func__); + USB_INFO("%s: unable to set lpm\n", __func__); #endif } static void usb_reset(struct usb_info *ui) { - unsigned long flags; - printk(KERN_INFO "hsusb: reset controller\n"); + USB_INFO("hsusb: reset controller\n"); - spin_lock_irqsave(&ui->lock, flags); - ui->running = 0; - spin_unlock_irqrestore(&ui->lock, flags); + atomic_set(&ui->running, 0); /* disable usb interrupts */ writel(0, USB_USBINTR); @@ -1523,15 +1673,9 @@ static void usb_reset(struct usb_info *ui) configure_endpoints(ui); /* marking us offline will cause ept queue attempts to fail */ - ui->online = 0; + atomic_set(&ui->online, 0); - /* terminate any pending transactions */ - flush_all_endpoints(ui); - - if (ui->driver) { - printk(KERN_INFO "usb: notify offline\n"); - ui->driver->disconnect(&ui->gadget); - } + handle_notify_offline(ui); /* enable interrupts */ writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR); @@ -1539,9 +1683,7 @@ static void usb_reset(struct usb_info *ui) /* go to RUN mode (D+ pullup enable) */ msm72k_pullup(&ui->gadget, 1); - spin_lock_irqsave(&ui->lock, flags); - ui->running = 1; - spin_unlock_irqrestore(&ui->lock, flags); + atomic_set(&ui->running, 1); } static void usb_start(struct usb_info *ui) @@ -1550,13 +1692,28 @@ static void usb_start(struct usb_info *ui) 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*/ +#ifndef CONFIG_ARCH_MSM8X60 + if (vbus) { + ui->flags |= USB_FLAG_VBUS_ONLINE; + if (ui->change_phy_voltage) + ui->change_phy_voltage(1); + } 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); +#endif queue_work(ui->usb_wq, &ui->work); spin_unlock_irqrestore(&ui->lock, flags); } static int usb_free(struct usb_info *ui, int ret) { - INFO("usb_free(%d)\n", ret); + USB_INFO("%s(%d)\n", __func__, ret); if (ui->irq) free_irq(ui->irq, 0); @@ -1587,7 +1744,7 @@ static void usb_do_work_check_vbus(struct usb_info *ui) spin_lock_irqsave(&ui->lock, iflags); #if defined(CONFIG_USB_BYPASS_VBUS_NOTIFY) ui->flags |= USB_FLAG_VBUS_ONLINE; - pr_info("usb: fake vbus\n"); + USB_INFO("fake vbus\n"); #else if (vbus) ui->flags |= USB_FLAG_VBUS_ONLINE; @@ -1600,9 +1757,11 @@ static void usb_do_work_check_vbus(struct usb_info *ui) static void usb_lpm_enter(struct usb_info *ui) { unsigned long iflags; + if (ui->in_lpm) return; - printk(KERN_INFO "usb: lpm enter\n"); + + USB_INFO("lpm enter\n"); spin_lock_irqsave(&ui->lock, iflags); usb_suspend_phy(ui); if (ui->otgclk) @@ -1613,16 +1772,34 @@ static void usb_lpm_enter(struct usb_info *ui) clk_disable(ui->coreclk); clk_set_rate(ui->ebi1clk, 0); ui->in_lpm = 1; + if (ui->pclk_src) + clk_disable(ui->pclk_src); spin_unlock_irqrestore(&ui->lock, iflags); + + if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/ + USB_INFO("idle_wake_unlock and perf unlock\n"); + wake_unlock(&vbus_idle_wake_lock); + if (is_perf_lock_active(&usb_perf_lock)) + perf_unlock(&usb_perf_lock); + } } static void usb_lpm_exit(struct usb_info *ui) { + unsigned long iflags; + if (!ui->in_lpm) return; - printk(KERN_INFO "usb: lpm exit\n"); - clk_set_rate(ui->ebi1clk, 128000000); + + USB_INFO("lpm exit\n"); + spin_lock_irqsave(&ui->lock, iflags); +//#ifndef CONFIG_ARCH_MSM8X60 /* FIXME */ +// clk_set_rate(ui->ebi1clk, acpuclk_get_max_axi_rate()); +//#endif udelay(10); + if (ui->pclk_src) + clk_enable(ui->pclk_src); + if (ui->coreclk) clk_enable(ui->coreclk); clk_enable(ui->clk); @@ -1631,87 +1808,232 @@ static void usb_lpm_exit(struct usb_info *ui) clk_enable(ui->otgclk); usb_wakeup_phy(ui); ui->in_lpm = 0; + spin_unlock_irqrestore(&ui->lock, iflags); + + if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/ + USB_INFO("idle_wake_lock and perf lock\n"); + wake_lock(&vbus_idle_wake_lock); + if (!is_perf_lock_active(&usb_perf_lock)) + perf_lock(&usb_perf_lock); + } } +static void do_usb_hub_disable(struct work_struct *w) +{ + struct usb_info *ui = container_of(w, struct usb_info, usb_hub_work); + + if (ui->usb_hub_enable) + ui->usb_hub_enable(false); +} + +#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); + cancel_delayed_work(&ui->dock_work); + queue_delayed_work(ui->usb_wq, &ui->dock_work_isr, DOCK_DET_DELAY); + return IRQ_HANDLED; +} +static void dock_isr_work(struct work_struct *w) +{ + struct usb_info *ui = container_of(w, + struct usb_info, dock_work_isr.work); + ui->dock_pin_state = gpio_get_value(ui->dock_pin_gpio); + + if (ui->dock_pin_state == 1) + set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW); + else + set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_HIGH); + queue_delayed_work(ui->usb_wq, &ui->dock_work, DOCK_DET_DELAY); + enable_irq(ui->dockpin_irq); +} +static void dock_detect_work(struct work_struct *w) +{ + struct usb_info *ui = container_of(w, struct usb_info, dock_work.work); + int value; + + value = gpio_get_value(ui->dock_pin_gpio); + USB_INFO("%s: dock_pin = %s\n", __func__, value ? "high" : "low"); + if (ui->dock_pin_state != value && (ui->dock_pin_state & 0x80) == 0) { + USB_ERR("%s: dock_pin_state changed\n", __func__); + return; + } + + if (value == 0 && vbus) { + if (ui->accessory_type == 3) + return; + set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_HIGH); + switch_set_state(&dock_switch, DOCK_STATE_DESK); + ui->accessory_type = 3; + USB_INFO("dock: set state %d\n", DOCK_STATE_DESK); + } else { + if (ui->accessory_type == 0) + return; + set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW); + switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED); + ui->accessory_type = 0; + USB_INFO("dock: set state %d\n", DOCK_STATE_UNDOCKED); + } +} +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); + if (!vbus) + set_irq_flags(ui->dockpin_irq, IRQF_VALID | IRQF_NOAUTOEN); + ret = request_irq(ui->dockpin_irq, dock_interrupt, + IRQF_TRIGGER_LOW, "dock_irq", ui); + if (ret < 0) { + USB_ERR("[GPIO DOCK] %s: request_irq failed\n", __func__); + return; + } + USB_INFO("%s: dock irq %d\n", __func__, ui->dockpin_irq); + ret = set_irq_wake(ui->dockpin_irq, 1); + if (ret < 0) { + USB_ERR("[GPIO DOCK] %s: set_irq_wake failed\n", __func__); + goto err; + } + + if (switch_dev_register(&dock_switch) < 0) { + USB_ERR("[GPIO DOCK] fail to register dock switch!\n"); + goto err; + } + + ret = device_create_file(dock_switch.dev, &dev_attr_status); + if (ret != 0) + USB_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) { unsigned n; int value; unsigned in_lpm; - msleep(100); value = gpio_get_value(ui->usb_id_pin_gpio); - printk(KERN_INFO "usb: usb ID pin = %d\n", value); + USB_INFO("%s: usb ID pin = %d\n", __func__, value); in_lpm = ui->in_lpm; if (value == 0) { - if (in_lpm) + if (in_lpm) { usb_lpm_exit(ui); + usb_reset(ui); + } n = readl(USB_OTGSC); /* ID pull-up register */ writel(n | OTGSC_IDPU, USB_OTGSC); msleep(100); - n = readl(USB_OTGSC); + n = readl(USB_OTGSC); if (n & OTGSC_ID) { - printk(KERN_INFO "usb: carkit inserted\n"); + USB_INFO("carkit inserted\n"); if ((board_mfg_mode() == 0) || (board_mfg_mode() == 1 && ui->mfg_usb_carkit_enable == 1)) { switch_set_state(&dock_switch, DOCK_STATE_CAR); - printk(KERN_INFO "carkit: set state %d\n", DOCK_STATE_CAR); + USB_INFO("carkit: set state %d\n", DOCK_STATE_CAR); } ui->accessory_type = 1; - } else - ui->accessory_type = 0; + } else { + USB_INFO("Credle inserted\n"); + switch_set_state(&dock_switch, DOCK_STATE_CREDLE); + ui->accessory_type = 5; + } if (in_lpm) usb_lpm_enter(ui); } else { if (ui->accessory_type == 1) - printk(KERN_INFO "usb: carkit removed\n"); + USB_INFO("carkit removed\n"); + else if (ui->accessory_type == 5) + USB_INFO("credle removed\n"); switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED); - printk(KERN_INFO "carkit: set state %d\n", DOCK_STATE_UNDOCKED); + USB_INFO("carkit: set state %d\n", DOCK_STATE_UNDOCKED); ui->accessory_type = 0; } } #ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC +static void mhl_detect(struct usb_info *ui) +{ + uint32_t adc_value = 0xffffffff; + + if (ui->config_usb_id_gpios) + ui->config_usb_id_gpios(1); + + htc_get_usb_accessory_adc_level(&adc_value); + USB_INFO("[2nd] accessory adc = 0x%x\n", adc_value); + + if (adc_value >= 0x5999 && adc_value <= 0x76B0) { + USB_INFO("MHL inserted\n"); + if (ui->usb_mhl_switch) + ui->usb_mhl_switch(1); + ui->accessory_type = 4; + } + if (ui->config_usb_id_gpios) + ui->config_usb_id_gpios(0); +} + static void accessory_detect_by_adc(struct usb_info *ui) { int value; + msleep(100); + value = gpio_get_value(ui->usb_id_pin_gpio); - printk(KERN_INFO "usb: usb ID pin = %d\n", value); + USB_INFO("%s: usb ID pin = %d\n", __func__, value); + if (value == 0) { uint32_t adc_value = 0xffffffff; htc_get_usb_accessory_adc_level(&adc_value); - printk(KERN_INFO "usb: accessory adc = 0x%x\n", adc_value); + USB_INFO("accessory adc = 0x%x\n", adc_value); if (adc_value >= 0x2112 && adc_value <= 0x3D53) { - printk(KERN_INFO "usb: headset inserted\n"); + USB_INFO("headset inserted\n"); ui->accessory_type = 2; - headset_ext_detect(USB_HEADSET); - } else if (adc_value >= 0x88A && adc_value <= 0x1E38) { - printk(KERN_INFO "usb: carkit inserted\n"); + headset_ext_detect(USB_AUDIO_OUT); + } else if (adc_value >= 0x1174 && adc_value <= 0x1E38) { + USB_INFO("carkit inserted\n"); ui->accessory_type = 1; if ((board_mfg_mode() == 0) || (board_mfg_mode() == 1 && ui->mfg_usb_carkit_enable == 1)) { switch_set_state(&dock_switch, DOCK_STATE_CAR); - printk(KERN_INFO "carkit: set state %d\n", DOCK_STATE_CAR); + USB_INFO("carkit: set state %d\n", DOCK_STATE_CAR); } + } else if (adc_value >= 0x0 && adc_value < 0x1174) { + mhl_detect(ui); } else ui->accessory_type = 0; } else { - if (ui->accessory_type == 2) { - printk(KERN_INFO "usb: headset removed\n"); - headset_ext_detect(NO_DEVICE); - } else if (ui->accessory_type == 1) { - printk(KERN_INFO "usb: carkit removed\n"); + switch (ui->accessory_type) { + case 1: + USB_INFO("carkit removed\n"); switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED); + ui->accessory_type = 0; + break; + case 2: + USB_INFO("headset removed\n"); + headset_ext_detect(USB_NO_HEADSET); + ui->accessory_type = 0; + break; + case 3: + /*MHL*/ + break; + default: + break; } - ui->accessory_type = 0; } - } #endif @@ -1743,7 +2065,7 @@ static irqreturn_t usbid_interrupt(int irq, void *data) struct usb_info *ui = data; disable_irq_nosync(ui->idpin_irq); - printk(KERN_INFO "usb: id interrupt\n"); + USB_INFO("id interrupt\n"); queue_work(ui->usb_wq, &ui->detect_work); return IRQ_HANDLED; } @@ -1751,34 +2073,36 @@ static irqreturn_t usbid_interrupt(int irq, void *data) static void accessory_detect_init(struct usb_info *ui) { int ret; - printk(KERN_INFO "%s: id pin %d\n", __func__, - ui->usb_id_pin_gpio); + USB_INFO("%s: id pin %d\n", __func__, ui->usb_id_pin_gpio); 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, "car_kit_irq", ui); if (ret < 0) { - printk(KERN_ERR "%s: request_irq failed\n", __func__); + USB_ERR("%s: request_irq failed\n", __func__); return; } ret = set_irq_wake(ui->idpin_irq, 1); if (ret < 0) { - printk(KERN_ERR "%s: set_irq_wake failed\n", __func__); + USB_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"); + USB_ERR(" 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"); + USB_WARNING("dev_attr_status failed\n"); + return; err: free_irq(ui->idpin_irq, 0); @@ -1787,6 +2111,47 @@ err: #endif #define DELAY_FOR_CHECK_CHG msecs_to_jiffies(300) + +static void charger_detect_by_uart(struct usb_info *ui) +{ + int is_china_ac; + + if (!vbus) + return; + + /*UART*/ + if (ui->usb_uart_switch) + ui->usb_uart_switch(1); + + 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); + USB_INFO("AC charger\n"); + } else { + ui->connect_type = CONNECT_TYPE_UNKNOWN; + queue_delayed_work(ui->usb_wq, &ui->chg_work, + DELAY_FOR_CHECK_CHG); + USB_INFO("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); + + usb_lpm_exit(ui); + usb_reset(ui); + } +} + static void charger_detect(struct usb_info *ui) { if (!vbus) @@ -1794,13 +2159,60 @@ static void charger_detect(struct usb_info *ui) msleep(10); /* detect shorted D+/D-, indicating AC power */ if ((readl(USB_PORTSC) & PORTSC_LS) != PORTSC_LS) { - printk(KERN_INFO "usb: not AC charger\n"); + USB_INFO("not AC charger\n"); ui->connect_type = CONNECT_TYPE_UNKNOWN; queue_delayed_work(ui->usb_wq, &ui->chg_work, DELAY_FOR_CHECK_CHG); + mod_timer(&ui->ac_detect_timer, jiffies + (3 * HZ)); } else { - printk(KERN_INFO "usb: AC charger\n"); - ui->connect_type = CONNECT_TYPE_AC; + if (ui->usb_id_pin_gpio != 0) { + if (gpio_get_value(ui->usb_id_pin_gpio) == 0) { + USB_INFO("9V AC charger\n"); + ui->connect_type = CONNECT_TYPE_9V_AC; + } else { + USB_INFO("AC charger\n"); + ui->connect_type = CONNECT_TYPE_AC; + } + } else { + USB_INFO("AC charger\n"); + ui->connect_type = CONNECT_TYPE_AC; + } + queue_work(ui->usb_wq, &ui->notifier_work); + writel(0x00080000, USB_USBCMD); + msleep(10); + usb_lpm_enter(ui); + if (ui->change_phy_voltage) + ui->change_phy_voltage(0); + } +} + +static void check_charger(struct work_struct *w) +{ + struct usb_info *ui = container_of(w, struct usb_info, chg_work.work); + if (disable_charger) { + USB_INFO("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); +} + +static void charger_detect_by_9v_gpio(struct usb_info *ui) +{ + if (!vbus) + return; + msleep(10); + if (gpio_get_value(ui->ac_9v_gpio) == 0) { + printk(KERN_INFO "not 9V AC charger\n"); + ui->connect_type = CONNECT_TYPE_UNKNOWN; + } else { + printk(KERN_INFO "9V AC charger\n"); + ui->connect_type = CONNECT_TYPE_9V_AC; + queue_work(ui->usb_wq, &ui->notifier_work); writel(0x00080000, USB_USBCMD); msleep(10); @@ -1808,13 +2220,6 @@ static void charger_detect(struct usb_info *ui) } } -static void check_charger(struct work_struct *w) -{ - struct usb_info *ui = container_of(w, struct usb_info, chg_work.work); - /* unknown charger */ - if (vbus && ui->connect_type == CONNECT_TYPE_UNKNOWN) - queue_work(ui->usb_wq, &ui->notifier_work); -} static void usb_do_work(struct work_struct *w) { @@ -1832,13 +2237,23 @@ static void usb_do_work(struct work_struct *w) /* give up if we have nothing to do */ if (flags == 0) break; + switch (ui->state) { case USB_STATE_IDLE: if (flags & USB_FLAG_START) { - pr_info("hsusb: IDLE -> ONLINE\n"); + USB_INFO("hsusb: IDLE -> ONLINE\n"); + usb_lpm_exit(ui); usb_reset(ui); - charger_detect(ui); + if (ui->china_ac_detect) + charger_detect_by_uart(ui); + else if (ui->ac_9v_gpio) + charger_detect_by_9v_gpio(ui); + else { + if (ui->usb_id_pin_gpio != 0) + msleep(200); + charger_detect(ui); + } ui->state = USB_STATE_ONLINE; #ifdef CONFIG_USB_ACCESSORY_DETECT @@ -1853,12 +2268,12 @@ static void usb_do_work(struct work_struct *w) * the signal to go offline, we must honor it */ if (flags & USB_FLAG_VBUS_OFFLINE) { - pr_info("hsusb: ONLINE -> OFFLINE\n"); + USB_INFO("hsusb: ONLINE -> OFFLINE\n"); + atomic_set(&ui->running, 0); + atomic_set(&ui->online, 0); /* synchronize with irq context */ spin_lock_irqsave(&ui->lock, iflags); - ui->running = 0; - ui->online = 0; writel(0x00080000, USB_USBCMD); spin_unlock_irqrestore(&ui->lock, iflags); @@ -1871,36 +2286,41 @@ static void usb_do_work(struct work_struct *w) msleep(5); } - /* terminate any transactions, etc */ - flush_all_endpoints(ui); - - if (ui->driver) { - printk(KERN_INFO "usb: notify offline\n"); - ui->driver->disconnect(&ui->gadget); - } + handle_notify_offline(ui); if (ui->phy_reset) ui->phy_reset(); /* power down phy, clock down usb */ usb_lpm_enter(ui); + ui->ac_detect_count = 0; + del_timer_sync(&ui->ac_detect_timer); + switch_set_state(&ui->sdev, 0); ui->state = USB_STATE_OFFLINE; usb_do_work_check_vbus(ui); break; } + + if (flags & USB_FLAG_CONFIGURED) { + switch_set_state(&ui->sdev, atomic_read(&ui->online)); + break; + } + if (flags & USB_FLAG_RESET) { - pr_info("hsusb: ONLINE -> RESET\n"); + USB_INFO("hsusb: ONLINE -> RESET\n"); if (ui->connect_type == CONNECT_TYPE_AC) { - pr_info("hsusb: RESET -> ONLINE\n"); + USB_INFO("hsusb: RESET -> ONLINE\n"); break; } + + atomic_set(&ui->online, 0); spin_lock_irqsave(&ui->lock, iflags); - ui->online = 0; msm72k_pullup(&ui->gadget, 0); spin_unlock_irqrestore(&ui->lock, iflags); usb_reset(ui); - pr_info("hsusb: RESET -> ONLINE\n"); + switch_set_state(&ui->sdev, 0); + USB_INFO("hsusb: RESET -> ONLINE\n"); break; } break; @@ -1909,10 +2329,19 @@ static void usb_do_work(struct work_struct *w) * present when we received the signal, go online. */ if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) { - pr_info("hsusb: OFFLINE -> ONLINE\n"); - usb_lpm_exit(ui); - usb_reset(ui); - charger_detect(ui); + USB_INFO("hsusb: OFFLINE -> ONLINE\n"); + + if (ui->china_ac_detect) + charger_detect_by_uart(ui); + else if (ui->ac_9v_gpio) { + usb_lpm_exit(ui); + usb_reset(ui); + charger_detect_by_9v_gpio(ui); + } else { + usb_lpm_exit(ui); + usb_reset(ui); + charger_detect(ui); + } ui->state = USB_STATE_ONLINE; usb_do_work_check_vbus(ui); @@ -1930,7 +2359,7 @@ void msm_hsusb_set_vbus_state(int online) { unsigned long flags = 0; struct usb_info *ui = the_usb_info; - printk(KERN_INFO "%s: %d\n", __func__, online); + USB_INFO("%s: %d\n", __func__, online); if (ui) spin_lock_irqsave(&ui->lock, flags); @@ -1942,14 +2371,61 @@ 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 (ui->change_phy_voltage) + ui->change_phy_voltage(online); + + if (online) { + /*USB*/ + if (ui->usb_uart_switch) + ui->usb_uart_switch(0); + } else { + /*turn off USB HUB*/ + if (ui->usb_hub_enable) + queue_work(ui->usb_wq, &ui->usb_hub_work); + + /*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); + + /*path should be switched to usb after mhl cable is removed*/ + if (ui->usb_mhl_switch && ui->accessory_type == 4) { + USB_INFO("MHL removed\n"); + ui->usb_mhl_switch(0); + ui->accessory_type = 0; + } + } + queue_work(ui->usb_wq, &ui->work); } } - if (ui) + if (ui) { spin_unlock_irqrestore(&ui->lock, flags); +#ifdef CONFIG_DOCK_ACCESSORY_DETECT + if (ui->dock_detect) { + if (vbus) + enable_irq(ui->dockpin_irq); + else { + disable_irq_nosync(ui->dockpin_irq); + if (cancel_delayed_work_sync(&ui->dock_work_isr)) + enable_irq(ui->dockpin_irq); + + if (cancel_delayed_work_sync(&ui->dock_work)) { + if (ui->dock_pin_state == 0) + set_irq_type(ui->dockpin_irq, + IRQF_TRIGGER_LOW); + } + if (ui->accessory_type == 3) { + ui->dock_pin_state |= 0x80; + queue_delayed_work(ui->usb_wq, &ui->dock_work, 0); + } + } + } +#endif + } } #if defined(CONFIG_DEBUG_FS) && 0 @@ -2100,6 +2576,7 @@ static int msm72k_disable(struct usb_ep *_ep) struct msm_endpoint *ept = to_msm_endpoint(_ep); usb_ept_enable(ept, 0, 0); + flush_endpoint(ept); return 0; } @@ -2140,7 +2617,7 @@ msm72k_queue(struct usb_ep *_ep, struct usb_request *req, gfp_t gfp_flags) if (!req->length) goto ep_queue_done; else { - if (ui->ep0_dir == USB_DIR_OUT) { + if (atomic_read(&ui->ep0_dir) == USB_DIR_OUT) { ep = &ui->ep0out; ep->ep.driver_data = ui->ep0in.ep.driver_data; } @@ -2287,10 +2764,10 @@ static int msm72k_pullup(struct usb_gadget *_gadget, int is_active) /* disable/enable D+ pullup */ if (is_active) { - pr_info("msm_hsusb: enable pullup\n"); + USB_INFO("msm_hsusb: enable pullup\n"); writel(cmd | 1, USB_USBCMD); } else { - pr_info("msm_hsusb: disable pullup\n"); + USB_INFO("msm_hsusb: disable pullup\n"); writel(cmd, USB_USBCMD); #ifndef CONFIG_ARCH_MSM7X00A @@ -2306,19 +2783,19 @@ static int msm72k_wakeup(struct usb_gadget *_gadget) struct usb_info *ui = container_of(_gadget, struct usb_info, gadget); unsigned long flags; - if (!ui->remote_wakeup) { - pr_err("%s: remote wakeup not supported\n", __func__); + if (!atomic_read(&ui->remote_wakeup)) { + USB_ERR("%s: remote wakeup not supported\n", __func__); return -ENOTSUPP; } - if (!ui->online) { - pr_err("%s: device is not configured\n", __func__); + if (!atomic_read(&ui->online)) { + USB_ERR("%s: device is not configured\n", __func__); return -ENODEV; } spin_lock_irqsave(&ui->lock, flags); if ((readl(USB_PORTSC) & PORTSC_SUSP) == PORTSC_SUSP) { - pr_info("%s: enabling force resume\n", __func__); + USB_INFO("%s: enabling force resume\n", __func__); writel(readl(USB_PORTSC) | PORTSC_FPR, USB_PORTSC); } spin_unlock_irqrestore(&ui->lock, flags); @@ -2344,14 +2821,71 @@ static ssize_t usb_remote_wakeup(struct device *dev, } static DEVICE_ATTR(wakeup, S_IWUSR, 0, usb_remote_wakeup); +static void ac_detect_expired(unsigned long _data) +{ + struct usb_info *ui = (struct usb_info *) _data; + u32 delay = 0; + + USB_INFO("%s: count = %d, connect_type = 0x%04x\n", __func__, + ui->ac_detect_count, ui->connect_type); + + if (ui->connect_type == CONNECT_TYPE_USB || ui->ac_detect_count >= 3) + 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 (ui->accessory_type == 1) { + USB_INFO("car mode charger\n"); + ui->connect_type = CONNECT_TYPE_AC; + queue_work(ui->usb_wq, &ui->notifier_work); + writel(0x00080000, USB_USBCMD); + mdelay(10); + usb_lpm_enter(ui); + return; + } + + ui->ac_detect_count++; + /* detect delay: 3 sec, 5 sec, 10 sec */ + if (ui->ac_detect_count == 1) + delay = 5 * HZ; + else if (ui->ac_detect_count == 2) + delay = 10 * HZ; + + mod_timer(&ui->ac_detect_timer, jiffies + delay); + } else { + if (ui->usb_id_pin_gpio != 0) { + if (gpio_get_value(ui->usb_id_pin_gpio) == 0) { + USB_INFO("9V AC charger\n"); + ui->connect_type = CONNECT_TYPE_9V_AC; + } else { + USB_INFO("AC charger\n"); + ui->connect_type = CONNECT_TYPE_AC; + } + } else { + USB_INFO("AC charger\n"); + ui->connect_type = CONNECT_TYPE_AC; + } + queue_work(ui->usb_wq, &ui->notifier_work); + writel(0x00080000, USB_USBCMD); + mdelay(10); + usb_lpm_enter(ui); + } +} + static int msm72k_probe(struct platform_device *pdev) { struct resource *res; struct usb_info *ui; int irq; int ret; + char *serialno = "000000000000"; - INFO("msm72k_probe\n"); + USB_INFO("msm72k_probe\n"); ui = kzalloc(sizeof(struct usb_info), GFP_KERNEL); if (!ui) return -ENOMEM; @@ -2365,13 +2899,33 @@ static int msm72k_probe(struct platform_device *pdev) 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; // DISABLED + ui->disable_usb_charger = pdata->disable_usb_charger; + ui->change_phy_voltage = pdata->change_phy_voltage; + ui->ldo_init = pdata->ldo_init; + ui->ldo_enable = pdata->ldo_enable; + ui->usb_mhl_switch = pdata->usb_mhl_switch; + ui->ac_9v_gpio = pdata->ac_9v_gpio; + + if (ui->ldo_init) + ui->ldo_init(1); + + if (ui->ldo_enable) + ui->ldo_enable(1); ui->accessory_detect = pdata->accessory_detect; - printk(KERN_INFO "usb: accessory detect %d\n", - ui->accessory_detect); + USB_INFO("accessory detect %d\n", ui->accessory_detect); ui->usb_id_pin_gpio = pdata->usb_id_pin_gpio; - printk(KERN_INFO "usb: id_pin_gpio %d\n", - pdata->usb_id_pin_gpio); + USB_INFO("id_pin_gpio %d\n", pdata->usb_id_pin_gpio); + + ui->dock_detect = pdata->dock_detect; + USB_INFO("dock detect %d\n", ui->dock_detect); + ui->dock_pin_gpio = pdata->dock_pin_gpio; + USB_INFO("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; } @@ -2393,7 +2947,7 @@ static int msm72k_probe(struct platform_device *pdev) if (!ui->pool) return usb_free(ui, -ENOMEM); - INFO("msm72k_probe() io=%p, irq=%d, dma=%p(%x)\n", + USB_INFO("msm72k_probe() io=%p, irq=%d, dma=%p(%x)\n", ui->addr, irq, ui->buf, ui->dma); #ifdef CONFIG_ARCH_MSM7X30 @@ -2403,6 +2957,19 @@ static int msm72k_probe(struct platform_device *pdev) if (IS_ERR(ui->clk)) return usb_free(ui, PTR_ERR(ui->clk)); + /* If USB Core is running its protocol engine based on PCLK, + * PCLK must be running at >60Mhz for correct HSUSB operation and + * USB core cannot tolerate frequency changes on PCLK. For such + * USB cores, vote for maximum clk frequency on pclk source + */ + if (ui->pclk_src_name) { + ui->pclk_src = clk_get(0, ui->pclk_src_name); + if (IS_ERR(ui->pclk_src)) + return usb_free(ui, PTR_ERR(ui->pclk_src)); + else + clk_set_rate(ui->pclk_src, 64000000); + } + ui->pclk = clk_get(&pdev->dev, "usb_hs_pclk"); if (IS_ERR(ui->pclk)) return usb_free(ui, PTR_ERR(ui->pclk)); @@ -2428,12 +2995,12 @@ static int msm72k_probe(struct platform_device *pdev) clk_enable(ui->otgclk); writel(0, USB_USBINTR); writel(0, USB_OTGSC); - if (ui->coreclk) - clk_disable(ui->coreclk); if (ui->otgclk) clk_disable(ui->otgclk); clk_disable(ui->pclk); clk_disable(ui->clk); + if (ui->coreclk) + clk_disable(ui->coreclk); ui->in_lpm = 1; ret = request_irq(irq, usb_interrupt, 0, pdev->name, ui); @@ -2457,12 +3024,19 @@ static int msm72k_probe(struct platform_device *pdev) /* initialize mfg serial number */ - if (board_mfg_mode() == 1) + if (board_mfg_mode() == 1) { use_mfg_serialno = 1; - else + wake_lock_init(&vbus_idle_wake_lock, WAKE_LOCK_IDLE, "usb_idle_lock"); + perf_lock_init(&usb_perf_lock, PERF_LOCK_HIGHEST, "usb"); + } else use_mfg_serialno = 0; - strncpy(mfg_df_serialno, "000000000000", strlen("000000000000")); + strncpy(mfg_df_serialno, serialno, strlen(serialno)); + ui->connect_type_ready = 0; + ui->ac_detect_count = 0; + ui->ac_detect_timer.data = (unsigned long) ui; + ui->ac_detect_timer.function = ac_detect_expired; + init_timer(&ui->ac_detect_timer); return 0; } @@ -2508,7 +3082,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) retval = driver->bind(&ui->gadget); if (retval) { - INFO("bind to driver %s --> error %d\n", + USB_INFO("bind to driver %s --> error %d\n", driver->driver.name, retval); device_del(&ui->gadget.dev); goto fail; @@ -2517,10 +3091,14 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) /* create sysfs node for remote wakeup */ retval = device_create_file(&ui->gadget.dev, &dev_attr_wakeup); if (retval != 0) - INFO("failed to create sysfs entry: (wakeup) error: (%d)\n", - retval); - INFO("msm72k_udc: registered gadget driver '%s'\n", + USB_INFO("failed to create sysfs entry: (wakeup) error:" + " (%d)\n", retval); + USB_INFO("msm72k_udc: registered gadget driver '%s'\n", driver->driver.name); + +#if defined(CONFIG_USB_BYPASS_VBUS_NOTIFY) + vbus = 1; +#endif usb_start(ui); return 0; @@ -2548,7 +3126,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) device_del(&dev->gadget.dev); - VDEBUG("unregistered gadget driver '%s'\n", driver->driver.name); + USB_DEBUG("unregistered gadget driver '%s'\n", driver->driver.name); return 0; } EXPORT_SYMBOL(usb_gadget_unregister_driver); diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 48267bc0..33ac6acb 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -291,9 +291,13 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_VENDOR_DESCRIPTION: pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); - length = strlen (rndis_per_dev_params [configNr].vendorDescr); - memcpy (outbuf, - rndis_per_dev_params [configNr].vendorDescr, length); + if ( rndis_per_dev_params [configNr].vendorDescr ) { + length = strlen (rndis_per_dev_params [configNr].vendorDescr); + memcpy (outbuf, + rndis_per_dev_params [configNr].vendorDescr, length); + } else { + outbuf[0] = 0; + } retval = 0; break;