Commit 6bc2b95e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-3.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Here are a bunch of USB patches for 3.3-rc1.

Nothing major, largest thing here is the removal of some drivers that
did not work at all.  Other than that, the normal collection of bugfixes
and new device ids.
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>

* tag 'usb-3.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (52 commits)
  uwb & wusb: fix kconfig error
  USB: Realtek cr: fix autopm scheduling while atomic
  USB: ftdi_sio: Add more identifiers
  xHCI: Cleanup isoc transfer ring when TD length mismatch found
  usb: musb: omap2430: minor cleanups.
  qcaux: add more Pantech UML190 and UML290 ports
  Revert "drivers: usb: Fix dependency for USB_HWA_HCD"
  usb: mv-otg - Fix build if CONFIG_USB is not set
  USB: cdc-wdm: Avoid hanging on interface with no USB_CDC_DMM_TYPE
  usb: add support for STA2X11 host driver
  drivers: usb: Fix dependency for USB_HWA_HCD
  kernel-doc: fix new warning in usb.h
  USB: OHCI: fix new compiler warnings
  usb: serial: kobil_sct: fix compile warning:
  drivers/usb/host/ehci-fsl.c: add missing iounmap
  USB: cdc-wdm: better allocate a buffer that is at least as big as we tell the USB core
  USB: cdc-wdm: call wake_up_all to allow driver to shutdown on device removal
  USB: cdc-wdm: use two mutexes to allow simultaneous read and write
  USB: cdc-wdm: updating desc->length must be protected by spin_lock
  USB: usbsevseg: fix max length
  ...
parents a14a8d93 a0701f04
......@@ -57,6 +57,8 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_MAX 16
/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
#define WDM_DEFAULT_BUFSIZE 256
static DEFINE_MUTEX(wdm_mutex);
......@@ -88,7 +90,8 @@ struct wdm_device {
int count;
dma_addr_t shandle;
dma_addr_t ihandle;
struct mutex lock;
struct mutex wlock;
struct mutex rlock;
wait_queue_head_t wait;
struct work_struct rxwork;
int werr;
......@@ -323,7 +326,7 @@ static ssize_t wdm_write
}
/* concurrent writes and disconnect */
r = mutex_lock_interruptible(&desc->lock);
r = mutex_lock_interruptible(&desc->wlock);
rv = -ERESTARTSYS;
if (r) {
kfree(buf);
......@@ -386,7 +389,7 @@ static ssize_t wdm_write
out:
usb_autopm_put_interface(desc->intf);
outnp:
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
outnl:
return rv < 0 ? rv : count;
}
......@@ -399,7 +402,7 @@ static ssize_t wdm_read
struct wdm_device *desc = file->private_data;
rv = mutex_lock_interruptible(&desc->lock); /*concurrent reads */
rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */
if (rv < 0)
return -ERESTARTSYS;
......@@ -467,14 +470,16 @@ static ssize_t wdm_read
for (i = 0; i < desc->length - cntr; i++)
desc->ubuf[i] = desc->ubuf[i + cntr];
spin_lock_irq(&desc->iuspin);
desc->length -= cntr;
spin_unlock_irq(&desc->iuspin);
/* in case we had outstanding data */
if (!desc->length)
clear_bit(WDM_READ, &desc->flags);
rv = cntr;
err:
mutex_unlock(&desc->lock);
mutex_unlock(&desc->rlock);
return rv;
}
......@@ -540,7 +545,8 @@ static int wdm_open(struct inode *inode, struct file *file)
}
intf->needs_remote_wakeup = 1;
mutex_lock(&desc->lock);
/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
if (!desc->count++) {
desc->werr = 0;
desc->rerr = 0;
......@@ -553,7 +559,7 @@ static int wdm_open(struct inode *inode, struct file *file)
} else {
rv = 0;
}
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
usb_autopm_put_interface(desc->intf);
out:
mutex_unlock(&wdm_mutex);
......@@ -565,9 +571,11 @@ static int wdm_release(struct inode *inode, struct file *file)
struct wdm_device *desc = file->private_data;
mutex_lock(&wdm_mutex);
mutex_lock(&desc->lock);
/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
desc->count--;
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
if (!desc->count) {
dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
......@@ -630,7 +638,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_cdc_dmm_desc *dmhd;
u8 *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
u16 maxcom = 0;
u16 maxcom = WDM_DEFAULT_BUFSIZE;
if (!buffer)
goto out;
......@@ -665,7 +673,8 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
if (!desc)
goto out;
mutex_init(&desc->lock);
mutex_init(&desc->rlock);
mutex_init(&desc->wlock);
spin_lock_init(&desc->iuspin);
init_waitqueue_head(&desc->wait);
desc->wMaxCommand = maxcom;
......@@ -716,7 +725,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto err;
desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
desc->bMaxPacketSize0,
desc->wMaxCommand,
GFP_KERNEL,
&desc->response->transfer_dma);
if (!desc->inbuf)
......@@ -779,11 +788,13 @@ static void wdm_disconnect(struct usb_interface *intf)
/* to terminate pending flushes */
clear_bit(WDM_IN_USE, &desc->flags);
spin_unlock_irqrestore(&desc->iuspin, flags);
mutex_lock(&desc->lock);
wake_up_all(&desc->wait);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
mutex_unlock(&desc->lock);
wake_up_all(&desc->wait);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
if (!desc->count)
cleanup(desc);
mutex_unlock(&wdm_mutex);
......@@ -798,8 +809,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
/* if this is an autosuspend the caller does the locking */
if (!PMSG_IS_AUTO(message))
mutex_lock(&desc->lock);
if (!PMSG_IS_AUTO(message)) {
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
}
spin_lock_irq(&desc->iuspin);
if (PMSG_IS_AUTO(message) &&
......@@ -815,8 +828,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
}
if (!PMSG_IS_AUTO(message))
mutex_unlock(&desc->lock);
if (!PMSG_IS_AUTO(message)) {
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
}
return rv;
}
......@@ -854,7 +869,8 @@ static int wdm_pre_reset(struct usb_interface *intf)
{
struct wdm_device *desc = usb_get_intfdata(intf);
mutex_lock(&desc->lock);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
/*
......@@ -876,7 +892,8 @@ static int wdm_post_reset(struct usb_interface *intf)
int rv;
rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
return 0;
}
......
......@@ -126,7 +126,6 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
struct dwc3_request *req)
{
struct dwc3 *dwc = dep->dwc;
u32 type;
int ret = 0;
req->request.actual = 0;
......@@ -149,20 +148,14 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
direction = !!(dep->flags & DWC3_EP0_DIR_IN);
if (dwc->ep0state == EP0_STATUS_PHASE) {
type = dwc->three_stage_setup
? DWC3_TRBCTL_CONTROL_STATUS3
: DWC3_TRBCTL_CONTROL_STATUS2;
} else if (dwc->ep0state == EP0_DATA_PHASE) {
type = DWC3_TRBCTL_CONTROL_DATA;
} else {
/* should never happen */
WARN_ON(1);
if (dwc->ep0state != EP0_DATA_PHASE) {
dev_WARN(dwc->dev, "Unexpected pending request\n");
return 0;
}
ret = dwc3_ep0_start_trans(dwc, direction,
req->request.dma, req->request.length, type);
req->request.dma, req->request.length,
DWC3_TRBCTL_CONTROL_DATA);
dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
DWC3_EP0_DIR_IN);
} else if (dwc->delayed_status) {
......
......@@ -101,7 +101,7 @@ void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
if (req->request.num_mapped_sgs) {
req->request.dma = DMA_ADDR_INVALID;
dma_unmap_sg(dwc->dev, req->request.sg,
req->request.num_sgs,
req->request.num_mapped_sgs,
req->direction ? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
......
......@@ -175,13 +175,12 @@ int config_ep_by_speed(struct usb_gadget *g,
_ep->comp_desc = comp_desc;
if (g->speed == USB_SPEED_SUPER) {
switch (usb_endpoint_type(_ep->desc)) {
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
_ep->maxburst = comp_desc->bMaxBurst;
break;
case USB_ENDPOINT_XFER_ISOC:
/* mult: bits 1:0 of bmAttributes */
_ep->mult = comp_desc->bmAttributes & 0x3;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
_ep->maxburst = comp_desc->bMaxBurst;
break;
default:
/* Do nothing for control endpoints */
......
......@@ -126,7 +126,7 @@ ep_matches (
* descriptor and see if the EP matches it
*/
if (usb_endpoint_xfer_bulk(desc)) {
if (ep_comp) {
if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) {
num_req_streams = ep_comp->bmAttributes & 0x1f;
if (num_req_streams > ep->max_streams)
return 0;
......
......@@ -3123,15 +3123,15 @@ fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c,
struct fsg_module_parameters {
char *file[FSG_MAX_LUNS];
int ro[FSG_MAX_LUNS];
int removable[FSG_MAX_LUNS];
int cdrom[FSG_MAX_LUNS];
int nofua[FSG_MAX_LUNS];
bool ro[FSG_MAX_LUNS];
bool removable[FSG_MAX_LUNS];
bool cdrom[FSG_MAX_LUNS];
bool nofua[FSG_MAX_LUNS];
unsigned int file_count, ro_count, removable_count, cdrom_count;
unsigned int nofua_count;
unsigned int luns; /* nluns */
int stall; /* can_stall */
bool stall; /* can_stall */
};
#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
......
......@@ -1430,7 +1430,7 @@ static void setup_received_irq(struct fsl_udc *udc,
int pipe = get_pipe_by_windex(wIndex);
struct fsl_ep *ep;
if (wValue != 0 || wLength != 0 || pipe > udc->max_ep)
if (wValue != 0 || wLength != 0 || pipe >= udc->max_ep)
break;
ep = get_ep_by_pipe(udc, pipe);
......@@ -1673,7 +1673,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
if (!bit_pos)
return;
for (i = 0; i < udc->max_ep * 2; i++) {
for (i = 0; i < udc->max_ep; i++) {
ep_num = i >> 1;
direction = i % 2;
......
......@@ -11,11 +11,6 @@
/* #undef DEBUG */
/* #undef VERBOSE_DEBUG */
#if defined(CONFIG_USB_LANGWELL_OTG)
#define OTG_TRANSCEIVER
#endif
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
......@@ -1522,8 +1517,7 @@ static void langwell_udc_stop(struct langwell_udc *dev)
/* stop all USB activities */
static void stop_activity(struct langwell_udc *dev,
struct usb_gadget_driver *driver)
static void stop_activity(struct langwell_udc *dev)
{
struct langwell_ep *ep;
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
......@@ -1535,9 +1529,9 @@ static void stop_activity(struct langwell_udc *dev,
}
/* report disconnect; the driver is already quiesced */
if (driver) {
if (dev->driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
......@@ -1925,11 +1919,10 @@ static int langwell_stop(struct usb_gadget *g,
/* stop all usb activities */
dev->gadget.speed = USB_SPEED_UNKNOWN;
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
stop_activity(dev);
spin_unlock_irqrestore(&dev->lock, flags);
device_remove_file(&dev->pdev->dev, &dev_attr_function);
......@@ -2315,13 +2308,9 @@ static void handle_setup_packet(struct langwell_udc *dev,
if (!gadget_is_otg(&dev->gadget))
break;
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) {
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
dev->gadget.b_hnp_enable = 1;
#ifdef OTG_TRANSCEIVER
if (!dev->lotg->otg.default_a)
dev->lotg->hsm.b_hnp_enable = 1;
#endif
} else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
dev->gadget.a_hnp_support = 1;
else if (setup->bRequest ==
USB_DEVICE_A_ALT_HNP_SUPPORT)
......@@ -2733,7 +2722,7 @@ static void handle_usb_reset(struct langwell_udc *dev)
dev->bus_reset = 1;
/* reset all the queues, stop all USB activities */
stop_activity(dev, dev->driver);
stop_activity(dev);
dev->usb_state = USB_STATE_DEFAULT;
} else {
dev_vdbg(&dev->pdev->dev, "device controller reset\n");
......@@ -2741,7 +2730,7 @@ static void handle_usb_reset(struct langwell_udc *dev)
langwell_udc_reset(dev);
/* reset all the queues, stop all USB activities */
stop_activity(dev, dev->driver);
stop_activity(dev);
/* reset ep0 dQH and endptctrl */
ep0_reset(dev);
......@@ -2752,12 +2741,6 @@ static void handle_usb_reset(struct langwell_udc *dev)
dev->usb_state = USB_STATE_ATTACHED;
}
#ifdef OTG_TRANSCEIVER
/* refer to USB OTG 6.6.2.3 b_hnp_en is cleared */
if (!dev->lotg->otg.default_a)
dev->lotg->hsm.b_hnp_enable = 0;
#endif
dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
}
......@@ -2770,29 +2753,6 @@ static void handle_bus_suspend(struct langwell_udc *dev)
dev->resume_state = dev->usb_state;
dev->usb_state = USB_STATE_SUSPENDED;
#ifdef OTG_TRANSCEIVER
if (dev->lotg->otg.default_a) {
if (dev->lotg->hsm.b_bus_suspend_vld == 1) {
dev->lotg->hsm.b_bus_suspend = 1;
/* notify transceiver the state changes */
if (spin_trylock(&dev->lotg->wq_lock)) {
langwell_update_transceiver();
spin_unlock(&dev->lotg->wq_lock);
}
}
dev->lotg->hsm.b_bus_suspend_vld++;
} else {
if (!dev->lotg->hsm.a_bus_suspend) {
dev->lotg->hsm.a_bus_suspend = 1;
/* notify transceiver the state changes */
if (spin_trylock(&dev->lotg->wq_lock)) {
langwell_update_transceiver();
spin_unlock(&dev->lotg->wq_lock);
}
}
}
#endif
/* report suspend to the driver */
if (dev->driver) {
if (dev->driver->suspend) {
......@@ -2823,11 +2783,6 @@ static void handle_bus_resume(struct langwell_udc *dev)
if (dev->pdev->device != 0x0829)
langwell_phy_low_power(dev, 0);
#ifdef OTG_TRANSCEIVER
if (dev->lotg->otg.default_a == 0)
dev->lotg->hsm.a_bus_suspend = 0;
#endif
/* report resume to the driver */
if (dev->driver) {
if (dev->driver->resume) {
......@@ -3020,7 +2975,6 @@ static void langwell_udc_remove(struct pci_dev *pdev)
dev->done = &done;
#ifndef OTG_TRANSCEIVER
/* free dTD dma_pool and dQH */
if (dev->dtd_pool)
dma_pool_destroy(dev->dtd_pool);
......@@ -3032,7 +2986,6 @@ static void langwell_udc_remove(struct pci_dev *pdev)
/* release SRAM caching */
if (dev->has_sram && dev->got_sram)
sram_deinit(dev);
#endif
if (dev->status_req) {
kfree(dev->status_req->req.buf);
......@@ -3045,7 +2998,6 @@ static void langwell_udc_remove(struct pci_dev *pdev)
if (dev->got_irq)
free_irq(pdev->irq, dev);
#ifndef OTG_TRANSCEIVER
if (dev->cap_regs)
iounmap(dev->cap_regs);
......@@ -3055,13 +3007,6 @@ static void langwell_udc_remove(struct pci_dev *pdev)
if (dev->enabled)
pci_disable_device(pdev);
#else
if (dev->transceiver) {
otg_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
dev->lotg = NULL;
}
#endif
dev->cap_regs = NULL;
......@@ -3072,9 +3017,7 @@ static void langwell_udc_remove(struct pci_dev *pdev)
device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
device_remove_file(&pdev->dev, &dev_attr_remote_wakeup);
#ifndef OTG_TRANSCEIVER
pci_set_drvdata(pdev, NULL);
#endif
/* free dev, wait for the release() finished */
wait_for_completion(&done);
......@@ -3089,9 +3032,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct langwell_udc *dev;
#ifndef OTG_TRANSCEIVER
unsigned long resource, len;
#endif
void __iomem *base = NULL;
size_t size;
int retval;
......@@ -3109,16 +3050,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
dev->pdev = pdev;
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
#ifdef OTG_TRANSCEIVER
/* PCI device is already enabled by otg_transceiver driver */
dev->enabled = 1;
/* mem region and register base */
dev->region = 1;
dev->transceiver = otg_get_transceiver();
dev->lotg = otg_to_langwell(dev->transceiver);
base = dev->lotg->regs;
#else
pci_set_drvdata(pdev, dev);
/* now all the pci goodies ... */
......@@ -3139,7 +3070,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
dev->region = 1;
base = ioremap_nocache(resource, len);
#endif
if (base == NULL) {
dev_err(&dev->pdev->dev, "can't map memory\n");
retval = -EFAULT;
......@@ -3163,7 +3093,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
dev->got_sram = 0;
dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram);
#ifndef OTG_TRANSCEIVER
/* enable SRAM caching if detected */
if (dev->has_sram && !dev->got_sram)
sram_init(dev);
......@@ -3182,7 +3111,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
goto error;
}
dev->got_irq = 1;
#endif
/* set stopped bit */
dev->stopped = 1;
......@@ -3257,10 +3185,8 @@ static int langwell_udc_probe(struct pci_dev *pdev,
dev->remote_wakeup = 0;
dev->dev_status = 1 << USB_DEVICE_SELF_POWERED;
#ifndef OTG_TRANSCEIVER
/* reset device controller */
langwell_udc_reset(dev);
#endif
/* initialize gadget structure */
dev->gadget.ops = &langwell_ops; /* usb_gadget_ops */
......@@ -3268,9 +3194,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */
dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
#ifdef OTG_TRANSCEIVER
dev->gadget.is_otg = 1; /* support otg mode */
#endif
/* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&dev->gadget.dev, "gadget");
......@@ -3282,10 +3205,8 @@ static int langwell_udc_probe(struct pci_dev *pdev,
/* controller endpoints reinit */
eps_reinit(dev);
#ifndef OTG_TRANSCEIVER
/* reset ep0 dQH and endptctrl */
ep0_reset(dev);
#endif
/* create dTD dma_pool resource */
dev->dtd_pool = dma_pool_create("langwell_dtd",
......@@ -3367,7 +3288,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
spin_lock_irq(&dev->lock);
/* stop all usb activities */
stop_activity(dev, dev->driver);
stop_activity(dev);
spin_unlock_irq(&dev->lock);
/* free dTD dma_pool and dQH */
......@@ -3525,22 +3446,14 @@ static struct pci_driver langwell_pci_driver = {
static int __init init(void)
{
#ifdef OTG_TRANSCEIVER
return langwell_register_peripheral(&langwell_pci_driver);
#else
return pci_register_driver(&langwell_pci_driver);
#endif
}
module_init(init);
static void __exit cleanup(void)
{
#ifdef OTG_TRANSCEIVER
return langwell_unregister_peripheral(&langwell_pci_driver);
#else
pci_unregister_driver(&langwell_pci_driver);
#endif
}
module_exit(cleanup);
......
......@@ -8,7 +8,6 @@
*/
#include <linux/usb/langwell_udc.h>
#include <linux/usb/langwell_otg.h>
/*-------------------------------------------------------------------------*/
......
......@@ -598,16 +598,16 @@ static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
| USB_5GBPS_OPERATION),
.bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT,
.bU2DevExitLat = USB_DEFAULT_U2_DEV_EXIT_LAT,
.bU2DevExitLat = cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT),
};
static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
.bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS,
.wTotalLength = USB_DT_BOS_SIZE
.wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE
+ USB_DT_USB_EXT_CAP_SIZE
+ USB_DT_USB_SS_CAP_SIZE,
+ USB_DT_USB_SS_CAP_SIZE),
.bNumDeviceCaps = 2,
};
......
......@@ -125,7 +125,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
*/
if (pdata->init && pdata->init(pdev)) {
retval = -ENODEV;
goto err3;
goto err4;
}
/* Enable USB controller, 83xx or 8536 */
......
......@@ -276,6 +276,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
/* Serial Bus Release Number is at PCI 0x60 offset */
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
if (pdev->vendor == PCI_VENDOR_ID_STMICRO
&& pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
ehci->sbrn = 0x20; /* ConneXT has no sbrn register */
/* Keep this around for a while just in case some EHCI
* implementation uses legacy PCI PM support. This test
......@@ -526,6 +529,9 @@ static const struct pci_device_id pci_ids [] = { {
/* handle any USB 2.0 EHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),
.driver_data = (unsigned long) &ehci_pci_hc_driver,
}, {
PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_HOST),
.driver_data = (unsigned long) &ehci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};
......
......@@ -82,6 +82,14 @@ urb_print(struct urb * urb, char * str, int small, int status)
ohci_dbg(ohci,format, ## arg ); \
} while (0);
/* Version for use where "next" is the address of a local variable */
#define ohci_dbg_nosw(ohci, next, size, format, arg...) \
do { \
unsigned s_len; \
s_len = scnprintf(*next, *size, format, ## arg); \
*size -= s_len; *next += s_len; \
} while (0);
static void ohci_dump_intr_mask (
struct ohci_hcd *ohci,
......@@ -653,7 +661,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
/* dump driver info, then registers in spec order */
ohci_dbg_sw (ohci, &next, &size,
ohci_dbg_nosw(ohci, &next, &size,
"bus %s, device %s\n"
"%s\n"
"%s\n",
......@@ -672,7 +680,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
/* hcca */
if (ohci->hcca)
ohci_dbg_sw (ohci, &next, &size,
ohci_dbg_nosw(ohci, &next, &size,
"hcca frame 0x%04x\n", ohci_frame_no(ohci));
/* other registers mostly affect frame timings */
......
......@@ -397,6 +397,10 @@ static const struct pci_device_id pci_ids [] = { {
/* handle any USB OHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0),
.driver_data = (unsigned long) &ohci_pci_hc_driver,
}, {
/* The device in the ConneXT I/O hub has no class reg */
PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_OHCI),
.driver_data = (unsigned long) &ohci_pci_hc_driver,
}, { /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE (pci, pci_ids);
......
......@@ -1204,6 +1204,7 @@ static void handle_vendor_event(struct xhci_hcd *xhci,
*
* Returns a zero-based port number, which is suitable for indexing into each of
* the split roothubs' port arrays and bus state arrays.
* Add one to it in order to call xhci_find_slot_id_by_port.
*/
static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
struct xhci_hcd *xhci, u32 port_id)
......@@ -1324,7 +1325,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
xhci_set_link_state(xhci, port_array, faked_port_index,
XDEV_U0);
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
faked_port_index);
faked_port_index + 1);
if (!slot_id) {
xhci_dbg(xhci, "slot_id is zero\n");
goto cleanup;
......@@ -3323,7 +3324,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Check TD length */
if (running_total != td_len) {
xhci_err(xhci, "ISOC TD length unmatch\n");
return -EINVAL;
ret = -EINVAL;
goto cleanup;
}
}
......
......@@ -37,9 +37,6 @@ static int emi26_set_reset(struct usb_device *dev, unsigned char reset_bit);
static int emi26_load_firmware (struct usb_device *dev);
static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *id);
static void emi26_disconnect(struct usb_interface *intf);
static int __init emi26_init (void);
static void __exit emi26_exit (void);
/* thanks to drivers/usb/serial/keyspan_pda.c code */
static int emi26_writememory (struct usb_device *dev, int address,
......
......@@ -46,9 +46,6 @@ static int emi62_set_reset(struct usb_device *dev, unsigned char reset_bit);
static int emi62_load_firmware (struct usb_device *dev);
static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id);
static void emi62_disconnect(struct usb_interface *intf);
static int __init emi62_init (void);
static void __exit emi62_exit (void);
/* thanks to drivers/usb/serial/keyspan_pda.c code */
static int emi62_writememory(struct usb_device *dev, int address,
......
......@@ -24,7 +24,7 @@
#define VENDOR_ID 0x0fc5
#define PRODUCT_ID 0x1227
#define MAXLEN 6
#define MAXLEN 8
/* table of devices that work with this driver */
static const struct usb_device_id id_table[] = {
......
......@@ -33,9 +33,6 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <mach/hardware.h>
#include <mach/memory.h>
#include <asm/gpio.h>
#include <mach/cputype.h>
#include <asm/mach-types.h>
......
......@@ -981,6 +981,9 @@ static void musb_shutdown(struct platform_device *pdev)
unsigned long flags;
pm_runtime_get_sync(musb->controller);
musb_gadget_cleanup(musb);
spin_lock_irqsave(&musb->lock, flags);
musb_platform_disable(musb);
musb_generic_disable(musb);
......@@ -1827,8 +1830,6 @@ static void musb_free(struct musb *musb)
sysfs_remove_group(&musb->controller->kobj, &musb_attr_group);
#endif
musb_gadget_cleanup(musb);
if (musb->nIrq >= 0) {
if (musb->irq_wake)
disable_irq_wake(musb->nIrq);
......
......@@ -222,7 +222,6 @@ static inline void omap2430_low_level_init(struct musb *musb)
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
}
/* blocking notifier support */
static int musb_otg_notifications(struct notifier_block *nb,
unsigned long event, void *unused)
{
......@@ -231,7 +230,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
musb->xceiv_event = event;
schedule_work(&musb->otg_notifier_work);
return 0;
return NOTIFY_OK;
}
static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
......@@ -386,6 +385,7 @@ static void omap2430_musb_disable(struct musb *musb)
static int omap2430_musb_exit(struct musb *musb)
{
del_timer_sync(&musb_idle_timer);
cancel_work_sync(&musb->otg_notifier_work);
omap2430_low_level_exit(musb);
otg_put_transceiver(musb->xceiv);
......
......@@ -86,20 +86,6 @@ config NOP_USB_XCEIV
built-in with usb ip or which are autonomous and doesn't require any
phy programming such as ISP1x04 etc.
config USB_LANGWELL_OTG
tristate "Intel Langwell USB OTG dual-role support"
depends on USB && PCI && INTEL_SCU_IPC
select USB_OTG
select USB_OTG_UTILS
help
Say Y here if you want to build Intel Langwell USB OTG
transciever driver in kernel. This driver implements role
switch between EHCI host driver and Langwell USB OTG
client driver.
To compile this driver as a module, choose M here: the
module will be called langwell_otg.
config USB_MSM_OTG
tristate "OTG support for Qualcomm on-chip USB controller"
depends on (USB || USB_GADGET) && ARCH_MSM
......@@ -124,7 +110,7 @@ config AB8500_USB
config FSL_USB2_OTG
bool "Freescale USB OTG Transceiver Driver"
depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2
depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 && USB_SUSPEND
select USB_OTG
select USB_OTG_UTILS
help
......@@ -132,7 +118,7 @@ config FSL_USB2_OTG
config USB_MV_OTG
tristate "Marvell USB OTG support"
depends on USB_MV_UDC
depends on USB_MV_UDC && USB_SUSPEND
select USB_OTG
select USB_OTG_UTILS
help
......
......@@ -13,7 +13,6 @@ obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o
obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o
obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
obj-$(CONFIG_USB_ULPI) += ulpi.o
obj-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi_viewport.o
......
/*
* Intel Langwell USB OTG transceiver driver
* Copyright (C) 2008 - 2010, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/* This driver helps to switch Langwell OTG controller function between host
* and peripheral. It works with EHCI driver and Langwell client controller
* driver together.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include <linux/usb/hcd.h>
#include <linux/notifier.h>
#include <linux/delay.h>
#include <asm/intel_scu_ipc.h>
#include <linux/usb/langwell_otg.h>
#define DRIVER_DESC "Intel Langwell USB OTG transceiver driver"
#define DRIVER_VERSION "July 10, 2010"
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
static const char driver_name[] = "langwell_otg";
static int langwell_otg_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void langwell_otg_remove(struct pci_dev *pdev);
static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message);
static int langwell_otg_resume(struct pci_dev *pdev);
static int langwell_otg_set_host(struct otg_transceiver *otg,
struct usb_bus *host);
static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
struct usb_gadget *gadget);
static int langwell_otg_start_srp(struct otg_transceiver *otg);
static const struct pci_device_id pci_ids[] = {{
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.vendor = 0x8086,
.device = 0x0811,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, { /* end: all zeroes */ }
};
static struct pci_driver otg_pci_driver = {
.name = (char *) driver_name,
.id_table = pci_ids,
.probe = langwell_otg_probe,
.remove = langwell_otg_remove,
.suspend = langwell_otg_suspend,
.resume = langwell_otg_resume,
};
/* HSM timers */
static inline struct langwell_otg_timer *otg_timer_initializer
(void (*function)(unsigned long), unsigned long expires, unsigned long data)
{
struct langwell_otg_timer *timer;
timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL);
if (timer == NULL)
return timer;
timer->function = function;
timer->expires = expires;
timer->data = data;
return timer;
}
static struct langwell_otg_timer *a_wait_vrise_tmr, *a_aidl_bdis_tmr,
*b_se0_srp_tmr, *b_srp_init_tmr;
static struct list_head active_timers;
static struct langwell_otg *the_transceiver;
/* host/client notify transceiver when event affects HNP state */
void langwell_update_transceiver(void)
{
struct langwell_otg *lnw = the_transceiver;
dev_dbg(lnw->dev, "transceiver is updated\n");
if (!lnw->qwork)
return ;
queue_work(lnw->qwork, &lnw->work);
}
EXPORT_SYMBOL(langwell_update_transceiver);
static int langwell_otg_set_host(struct otg_transceiver *otg,
struct usb_bus *host)
{
otg->host = host;
return 0;
}
static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
struct usb_gadget *gadget)
{
otg->gadget = gadget;
return 0;
}
static int langwell_otg_set_power(struct otg_transceiver *otg,
unsigned mA)
{
return 0;
}
/* A-device drives vbus, controlled through IPC commands */
static int langwell_otg_set_vbus(struct otg_transceiver *otg, bool enabled)
{
struct langwell_otg *lnw = the_transceiver;
u8 sub_id;
dev_dbg(lnw->dev, "%s <--- %s\n", __func__, enabled ? "on" : "off");
if (enabled)
sub_id = 0x8; /* Turn on the VBus */
else
sub_id = 0x9; /* Turn off the VBus */
if (intel_scu_ipc_simple_command(0xef, sub_id)) {
dev_dbg(lnw->dev, "Failed to set Vbus via IPC commands\n");
return -EBUSY;
}
dev_dbg(lnw->dev, "%s --->\n", __func__);
return 0;
}
/* charge vbus or discharge vbus through a resistor to ground */
static void langwell_otg_chrg_vbus(int on)
{
struct langwell_otg *lnw = the_transceiver;
u32 val;
val = readl(lnw->iotg.base + CI_OTGSC);
if (on)
writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC,
lnw->iotg.base + CI_OTGSC);
else
writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD,
lnw->iotg.base + CI_OTGSC);
}
/* Start SRP */
static int langwell_otg_start_srp(struct otg_transceiver *otg)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u32 val;
dev_dbg(lnw->dev, "%s --->\n", __func__);
val = readl(iotg->base + CI_OTGSC);
writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP,
iotg->base + CI_OTGSC);
/* Check if the data plus is finished or not */
msleep(8);
val = readl(iotg->base + CI_OTGSC);
if (val & (OTGSC_HADP | OTGSC_DP))
dev_dbg(lnw->dev, "DataLine SRP Error\n");
/* Disable interrupt - b_sess_vld */
val = readl(iotg->base + CI_OTGSC);
val &= (~(OTGSC_BSVIE | OTGSC_BSEIE));
writel(val, iotg->base + CI_OTGSC);
/* Start VBus SRP, drive vbus to generate VBus pulse */
iotg->otg.set_vbus(&iotg->otg, true);
msleep(15);
iotg->otg.set_vbus(&iotg->otg, false);
/* Enable interrupt - b_sess_vld*/
val = readl(iotg->base + CI_OTGSC);
dev_dbg(lnw->dev, "after VBUS pulse otgsc = %x\n", val);
val |= (OTGSC_BSVIE | OTGSC_BSEIE);
writel(val, iotg->base + CI_OTGSC);
/* If Vbus is valid, then update the hsm */
if (val & OTGSC_BSV) {
dev_dbg(lnw->dev, "no b_sess_vld interrupt\n");
lnw->iotg.hsm.b_sess_vld = 1;
langwell_update_transceiver();
}
dev_dbg(lnw->dev, "%s <---\n", __func__);
return 0;
}
/* stop SOF via bus_suspend */
static void langwell_otg_loc_sof(int on)
{
struct langwell_otg *lnw = the_transceiver;
struct usb_hcd *hcd;
int err;
dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "suspend" : "resume");
hcd = bus_to_hcd(lnw->iotg.otg.host);
if (on)
err = hcd->driver->bus_resume(hcd);
else
err = hcd->driver->bus_suspend(hcd);
if (err)
dev_dbg(lnw->dev, "Fail to resume/suspend USB bus - %d\n", err);
dev_dbg(lnw->dev, "%s <---\n", __func__);
}
static int langwell_otg_check_otgsc(void)
{
struct langwell_otg *lnw = the_transceiver;
u32 otgsc, usbcfg;
dev_dbg(lnw->dev, "check sync OTGSC and USBCFG registers\n");
otgsc = readl(lnw->iotg.base + CI_OTGSC);
usbcfg = readl(lnw->usbcfg);
dev_dbg(lnw->dev, "OTGSC = %08x, USBCFG = %08x\n",
otgsc, usbcfg);
dev_dbg(lnw->dev, "OTGSC_AVV = %d\n", !!(otgsc & OTGSC_AVV));
dev_dbg(lnw->dev, "USBCFG.VBUSVAL = %d\n",
!!(usbcfg & USBCFG_VBUSVAL));
dev_dbg(lnw->dev, "OTGSC_ASV = %d\n", !!(otgsc & OTGSC_ASV));
dev_dbg(lnw->dev, "USBCFG.AVALID = %d\n",
!!(usbcfg & USBCFG_AVALID));
dev_dbg(lnw->dev, "OTGSC_BSV = %d\n", !!(otgsc & OTGSC_BSV));
dev_dbg(lnw->dev, "USBCFG.BVALID = %d\n",
!!(usbcfg & USBCFG_BVALID));
dev_dbg(lnw->dev, "OTGSC_BSE = %d\n", !!(otgsc & OTGSC_BSE));
dev_dbg(lnw->dev, "USBCFG.SESEND = %d\n",
!!(usbcfg & USBCFG_SESEND));
/* Check USBCFG VBusValid/AValid/BValid/SessEnd */
if (!!(otgsc & OTGSC_AVV) ^ !!(usbcfg & USBCFG_VBUSVAL)) {
dev_dbg(lnw->dev, "OTGSC.AVV != USBCFG.VBUSVAL\n");
goto err;
}
if (!!(otgsc & OTGSC_ASV) ^ !!(usbcfg & USBCFG_AVALID)) {
dev_dbg(lnw->dev, "OTGSC.ASV != USBCFG.AVALID\n");
goto err;
}
if (!!(otgsc & OTGSC_BSV) ^ !!(usbcfg & USBCFG_BVALID)) {
dev_dbg(lnw->dev, "OTGSC.BSV != USBCFG.BVALID\n");
goto err;
}
if (!!(otgsc & OTGSC_BSE) ^ !!(usbcfg & USBCFG_SESEND)) {
dev_dbg(lnw->dev, "OTGSC.BSE != USBCFG.SESSEN\n");
goto err;
}
dev_dbg(lnw->dev, "OTGSC and USBCFG are synced\n");
return 0;
err:
dev_warn(lnw->dev, "OTGSC isn't equal to USBCFG\n");
return -EPIPE;
}
static void langwell_otg_phy_low_power(int on)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u8 val, phcd;
int retval;
dev_dbg(lnw->dev, "%s ---> %s mode\n",
__func__, on ? "Low power" : "Normal");
phcd = 0x40;
val = readb(iotg->base + CI_HOSTPC1 + 2);
if (on) {
/* Due to hardware issue, after set PHCD, sync will failed
* between USBCFG and OTGSC, so before set PHCD, check if
* sync is in process now. If the answer is "yes", then do
* not touch PHCD bit */
retval = langwell_otg_check_otgsc();
if (retval) {
dev_dbg(lnw->dev, "Skip PHCD programming..\n");
return ;
}
writeb(val | phcd, iotg->base + CI_HOSTPC1 + 2);
} else
writeb(val & ~phcd, iotg->base + CI_HOSTPC1 + 2);
dev_dbg(lnw->dev, "%s <--- done\n", __func__);
}
/* After drv vbus, add 5 ms delay to set PHCD */
static void langwell_otg_phy_low_power_wait(int on)
{
struct langwell_otg *lnw = the_transceiver;
dev_dbg(lnw->dev, "add 5ms delay before programing PHCD\n");
mdelay(5);
langwell_otg_phy_low_power(on);
}
/* Enable/Disable OTG interrupt */
static void langwell_otg_intr(int on)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u32 val;
dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
val = readl(iotg->base + CI_OTGSC);
/* OTGSC_INT_MASK doesn't contains 1msInt */
if (on) {
val = val | (OTGSC_INT_MASK);
writel(val, iotg->base + CI_OTGSC);
} else {
val = val & ~(OTGSC_INT_MASK);
writel(val, iotg->base + CI_OTGSC);
}
dev_dbg(lnw->dev, "%s <---\n", __func__);
}
/* set HAAR: Hardware Assist Auto-Reset */
static void langwell_otg_HAAR(int on)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u32 val;
dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
val = readl(iotg->base + CI_OTGSC);
if (on)
writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR,
iotg->base + CI_OTGSC);
else
writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR,
iotg->base + CI_OTGSC);
dev_dbg(lnw->dev, "%s <---\n", __func__);
}
/* set HABA: Hardware Assist B-Disconnect to A-Connect */
static void langwell_otg_HABA(int on)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u32 val;
dev_dbg(lnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
val = readl(iotg->base + CI_OTGSC);
if (on)
writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA,
iotg->base + CI_OTGSC);
else
writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA,
iotg->base + CI_OTGSC);
dev_dbg(lnw->dev, "%s <---\n", __func__);
}
static int langwell_otg_check_se0_srp(int on)
{
struct langwell_otg *lnw = the_transceiver;
int delay_time = TB_SE0_SRP * 10;
u32 val;
dev_dbg(lnw->dev, "%s --->\n", __func__);
do {
udelay(100);
if (!delay_time--)
break;
val = readl(lnw->iotg.base + CI_PORTSC1);
val &= PORTSC_LS;
} while (!val);
dev_dbg(lnw->dev, "%s <---\n", __func__);
return val;
}
/* The timeout callback function to set time out bit */
static void set_tmout(unsigned long indicator)
{
*(int *)indicator = 1;
}
void langwell_otg_nsf_msg(unsigned long indicator)
{
struct langwell_otg *lnw = the_transceiver;
switch (indicator) {
case 2:
case 4:
case 6:
case 7:
dev_warn(lnw->dev,
"OTG:NSF-%lu - deivce not responding\n", indicator);
break;
case 3:
dev_warn(lnw->dev,
"OTG:NSF-%lu - deivce not supported\n", indicator);
break;
default:
dev_warn(lnw->dev, "Do not have this kind of NSF\n");
break;
}
}
/* Initialize timers */
static int langwell_otg_init_timers(struct otg_hsm *hsm)
{
/* HSM used timers */
a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
(unsigned long)&hsm->a_wait_vrise_tmout);
if (a_wait_vrise_tmr == NULL)
return -ENOMEM;
a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
(unsigned long)&hsm->a_aidl_bdis_tmout);
if (a_aidl_bdis_tmr == NULL)
return -ENOMEM;
b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
(unsigned long)&hsm->b_se0_srp);
if (b_se0_srp_tmr == NULL)
return -ENOMEM;
b_srp_init_tmr = otg_timer_initializer(&set_tmout, TB_SRP_INIT,
(unsigned long)&hsm->b_srp_init_tmout);
if (b_srp_init_tmr == NULL)
return -ENOMEM;
return 0;
}
/* Free timers */
static void langwell_otg_free_timers(void)
{
kfree(a_wait_vrise_tmr);
kfree(a_aidl_bdis_tmr);
kfree(b_se0_srp_tmr);
kfree(b_srp_init_tmr);
}
/* The timeout callback function to set time out bit */
static void langwell_otg_timer_fn(unsigned long indicator)
{
struct langwell_otg *lnw = the_transceiver;
*(int *)indicator = 1;
dev_dbg(lnw->dev, "kernel timer - timeout\n");
langwell_update_transceiver();
}
/* kernel timer used instead of HW based interrupt */
static void langwell_otg_add_ktimer(enum langwell_otg_timer_type timers)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
unsigned long j = jiffies;
unsigned long data, time;
switch (timers) {
case TA_WAIT_VRISE_TMR:
iotg->hsm.a_wait_vrise_tmout = 0;
data = (unsigned long)&iotg->hsm.a_wait_vrise_tmout;
time = TA_WAIT_VRISE;
break;
case TA_WAIT_BCON_TMR:
iotg->hsm.a_wait_bcon_tmout = 0;
data = (unsigned long)&iotg->hsm.a_wait_bcon_tmout;
time = TA_WAIT_BCON;
break;
case TA_AIDL_BDIS_TMR:
iotg->hsm.a_aidl_bdis_tmout = 0;
data = (unsigned long)&iotg->hsm.a_aidl_bdis_tmout;
time = TA_AIDL_BDIS;
break;
case TB_ASE0_BRST_TMR:
iotg->hsm.b_ase0_brst_tmout = 0;
data = (unsigned long)&iotg->hsm.b_ase0_brst_tmout;
time = TB_ASE0_BRST;
break;
case TB_SRP_INIT_TMR:
iotg->hsm.b_srp_init_tmout = 0;
data = (unsigned long)&iotg->hsm.b_srp_init_tmout;
time = TB_SRP_INIT;
break;
case TB_SRP_FAIL_TMR:
iotg->hsm.b_srp_fail_tmout = 0;
data = (unsigned long)&iotg->hsm.b_srp_fail_tmout;
time = TB_SRP_FAIL;
break;
case TB_BUS_SUSPEND_TMR:
iotg->hsm.b_bus_suspend_tmout = 0;
data = (unsigned long)&iotg->hsm.b_bus_suspend_tmout;
time = TB_BUS_SUSPEND;
break;
default:
dev_dbg(lnw->dev, "unknown timer, cannot enable it\n");
return;
}
lnw->hsm_timer.data = data;
lnw->hsm_timer.function = langwell_otg_timer_fn;
lnw->hsm_timer.expires = j + time * HZ / 1000; /* milliseconds */
add_timer(&lnw->hsm_timer);
dev_dbg(lnw->dev, "add timer successfully\n");
}
/* Add timer to timer list */
static void langwell_otg_add_timer(void *gtimer)
{
struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
struct langwell_otg_timer *tmp_timer;
struct intel_mid_otg_xceiv *iotg = &the_transceiver->iotg;
u32 val32;
/* Check if the timer is already in the active list,
* if so update timer count
*/
list_for_each_entry(tmp_timer, &active_timers, list)
if (tmp_timer == timer) {
timer->count = timer->expires;
return;
}
timer->count = timer->expires;
if (list_empty(&active_timers)) {
val32 = readl(iotg->base + CI_OTGSC);
writel(val32 | OTGSC_1MSE, iotg->base + CI_OTGSC);
}
list_add_tail(&timer->list, &active_timers);
}
/* Remove timer from the timer list; clear timeout status */
static void langwell_otg_del_timer(void *gtimer)
{
struct langwell_otg *lnw = the_transceiver;
struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
struct langwell_otg_timer *tmp_timer, *del_tmp;
u32 val32;
list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
if (tmp_timer == timer)
list_del(&timer->list);
if (list_empty(&active_timers)) {
val32 = readl(lnw->iotg.base + CI_OTGSC);
writel(val32 & ~OTGSC_1MSE, lnw->iotg.base + CI_OTGSC);
}
}
/* Reduce timer count by 1, and find timeout conditions.*/
static int langwell_otg_tick_timer(u32 *int_sts)
{
struct langwell_otg *lnw = the_transceiver;
struct langwell_otg_timer *tmp_timer, *del_tmp;
int expired = 0;
list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
tmp_timer->count--;
/* check if timer expires */
if (!tmp_timer->count) {
list_del(&tmp_timer->list);
tmp_timer->function(tmp_timer->data);
expired = 1;
}
}
if (list_empty(&active_timers)) {
dev_dbg(lnw->dev, "tick timer: disable 1ms int\n");
*int_sts = *int_sts & ~OTGSC_1MSE;
}
return expired;
}
static void reset_otg(void)
{
struct langwell_otg *lnw = the_transceiver;
int delay_time = 1000;
u32 val;
dev_dbg(lnw->dev, "reseting OTG controller ...\n");
val = readl(lnw->iotg.base + CI_USBCMD);
writel(val | USBCMD_RST, lnw->iotg.base + CI_USBCMD);
do {
udelay(100);
if (!delay_time--)
dev_dbg(lnw->dev, "reset timeout\n");
val = readl(lnw->iotg.base + CI_USBCMD);
val &= USBCMD_RST;
} while (val != 0);
dev_dbg(lnw->dev, "reset done.\n");
}
static void set_host_mode(void)
{
struct langwell_otg *lnw = the_transceiver;
u32 val;
reset_otg();
val = readl(lnw->iotg.base + CI_USBMODE);
val = (val & (~USBMODE_CM)) | USBMODE_HOST;
writel(val, lnw->iotg.base + CI_USBMODE);
}
static void set_client_mode(void)
{
struct langwell_otg *lnw = the_transceiver;
u32 val;
reset_otg();
val = readl(lnw->iotg.base + CI_USBMODE);
val = (val & (~USBMODE_CM)) | USBMODE_DEVICE;
writel(val, lnw->iotg.base + CI_USBMODE);
}
static void init_hsm(void)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u32 val32;
/* read OTGSC after reset */
val32 = readl(lnw->iotg.base + CI_OTGSC);
dev_dbg(lnw->dev, "%s: OTGSC init value = 0x%x\n", __func__, val32);
/* set init state */
if (val32 & OTGSC_ID) {
iotg->hsm.id = 1;
iotg->otg.default_a = 0;
set_client_mode();
iotg->otg.state = OTG_STATE_B_IDLE;
} else {
iotg->hsm.id = 0;
iotg->otg.default_a = 1;
set_host_mode();
iotg->otg.state = OTG_STATE_A_IDLE;
}
/* set session indicator */
if (val32 & OTGSC_BSE)
iotg->hsm.b_sess_end = 1;
if (val32 & OTGSC_BSV)
iotg->hsm.b_sess_vld = 1;
if (val32 & OTGSC_ASV)
iotg->hsm.a_sess_vld = 1;
if (val32 & OTGSC_AVV)
iotg->hsm.a_vbus_vld = 1;
/* defautly power the bus */
iotg->hsm.a_bus_req = 1;
iotg->hsm.a_bus_drop = 0;
/* defautly don't request bus as B device */
iotg->hsm.b_bus_req = 0;
/* no system error */
iotg->hsm.a_clr_err = 0;
langwell_otg_phy_low_power_wait(1);
}
static void update_hsm(void)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u32 val32;
/* read OTGSC */
val32 = readl(lnw->iotg.base + CI_OTGSC);
dev_dbg(lnw->dev, "%s: OTGSC value = 0x%x\n", __func__, val32);
iotg->hsm.id = !!(val32 & OTGSC_ID);
iotg->hsm.b_sess_end = !!(val32 & OTGSC_BSE);
iotg->hsm.b_sess_vld = !!(val32 & OTGSC_BSV);
iotg->hsm.a_sess_vld = !!(val32 & OTGSC_ASV);
iotg->hsm.a_vbus_vld = !!(val32 & OTGSC_AVV);
}
static irqreturn_t otg_dummy_irq(int irq, void *_dev)
{
struct langwell_otg *lnw = the_transceiver;
void __iomem *reg_base = _dev;
u32 val;
u32 int_mask = 0;
val = readl(reg_base + CI_USBMODE);
if ((val & USBMODE_CM) != USBMODE_DEVICE)
return IRQ_NONE;
val = readl(reg_base + CI_USBSTS);
int_mask = val & INTR_DUMMY_MASK;
if (int_mask == 0)
return IRQ_NONE;
/* clear hsm.b_conn here since host driver can't detect it
* otg_dummy_irq called means B-disconnect happened.
*/
if (lnw->iotg.hsm.b_conn) {
lnw->iotg.hsm.b_conn = 0;
if (spin_trylock(&lnw->wq_lock)) {
langwell_update_transceiver();
spin_unlock(&lnw->wq_lock);
}
}
/* Clear interrupts */
writel(int_mask, reg_base + CI_USBSTS);
return IRQ_HANDLED;
}
static irqreturn_t otg_irq(int irq, void *_dev)
{
struct langwell_otg *lnw = _dev;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
u32 int_sts, int_en;
u32 int_mask = 0;
int flag = 0;
int_sts = readl(lnw->iotg.base + CI_OTGSC);
int_en = (int_sts & OTGSC_INTEN_MASK) >> 8;
int_mask = int_sts & int_en;
if (int_mask == 0)
return IRQ_NONE;
if (int_mask & OTGSC_IDIS) {
dev_dbg(lnw->dev, "%s: id change int\n", __func__);
iotg->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0;
dev_dbg(lnw->dev, "id = %d\n", iotg->hsm.id);
flag = 1;
}
if (int_mask & OTGSC_DPIS) {
dev_dbg(lnw->dev, "%s: data pulse int\n", __func__);
iotg->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0;
dev_dbg(lnw->dev, "data pulse = %d\n", iotg->hsm.a_srp_det);
flag = 1;
}
if (int_mask & OTGSC_BSEIS) {
dev_dbg(lnw->dev, "%s: b session end int\n", __func__);
iotg->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0;
dev_dbg(lnw->dev, "b_sess_end = %d\n", iotg->hsm.b_sess_end);
flag = 1;
}
if (int_mask & OTGSC_BSVIS) {
dev_dbg(lnw->dev, "%s: b session valid int\n", __func__);
iotg->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0;
dev_dbg(lnw->dev, "b_sess_vld = %d\n", iotg->hsm.b_sess_end);
flag = 1;
}
if (int_mask & OTGSC_ASVIS) {
dev_dbg(lnw->dev, "%s: a session valid int\n", __func__);
iotg->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0;
dev_dbg(lnw->dev, "a_sess_vld = %d\n", iotg->hsm.a_sess_vld);
flag = 1;
}
if (int_mask & OTGSC_AVVIS) {
dev_dbg(lnw->dev, "%s: a vbus valid int\n", __func__);
iotg->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0;
dev_dbg(lnw->dev, "a_vbus_vld = %d\n", iotg->hsm.a_vbus_vld);
flag = 1;
}
if (int_mask & OTGSC_1MSS) {
/* need to schedule otg_work if any timer is expired */
if (langwell_otg_tick_timer(&int_sts))
flag = 1;
}
writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask,
lnw->iotg.base + CI_OTGSC);
if (flag)
langwell_update_transceiver();
return IRQ_HANDLED;
}
static int langwell_otg_iotg_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = data;
int flag = 0;
if (iotg == NULL)
return NOTIFY_BAD;
if (lnw == NULL)
return NOTIFY_BAD;
switch (action) {
case MID_OTG_NOTIFY_CONNECT:
dev_dbg(lnw->dev, "Lnw OTG Notify Connect Event\n");
if (iotg->otg.default_a == 1)
iotg->hsm.b_conn = 1;
else
iotg->hsm.a_conn = 1;
flag = 1;
break;
case MID_OTG_NOTIFY_DISCONN:
dev_dbg(lnw->dev, "Lnw OTG Notify Disconnect Event\n");
if (iotg->otg.default_a == 1)
iotg->hsm.b_conn = 0;
else
iotg->hsm.a_conn = 0;
flag = 1;
break;
case MID_OTG_NOTIFY_HSUSPEND:
dev_dbg(lnw->dev, "Lnw OTG Notify Host Bus suspend Event\n");
if (iotg->otg.default_a == 1)
iotg->hsm.a_suspend_req = 1;
else
iotg->hsm.b_bus_req = 0;
flag = 1;
break;
case MID_OTG_NOTIFY_HRESUME:
dev_dbg(lnw->dev, "Lnw OTG Notify Host Bus resume Event\n");
if (iotg->otg.default_a == 1)
iotg->hsm.b_bus_resume = 1;
flag = 1;
break;
case MID_OTG_NOTIFY_CSUSPEND:
dev_dbg(lnw->dev, "Lnw OTG Notify Client Bus suspend Event\n");
if (iotg->otg.default_a == 1) {
if (iotg->hsm.b_bus_suspend_vld == 2) {
iotg->hsm.b_bus_suspend = 1;
iotg->hsm.b_bus_suspend_vld = 0;
flag = 1;
} else {
iotg->hsm.b_bus_suspend_vld++;
flag = 0;
}
} else {
if (iotg->hsm.a_bus_suspend == 0) {
iotg->hsm.a_bus_suspend = 1;
flag = 1;
}
}
break;
case MID_OTG_NOTIFY_CRESUME:
dev_dbg(lnw->dev, "Lnw OTG Notify Client Bus resume Event\n");
if (iotg->otg.default_a == 0)
iotg->hsm.a_bus_suspend = 0;
flag = 0;
break;
case MID_OTG_NOTIFY_HOSTADD:
dev_dbg(lnw->dev, "Lnw OTG Nofity Host Driver Add\n");
flag = 1;
break;
case MID_OTG_NOTIFY_HOSTREMOVE:
dev_dbg(lnw->dev, "Lnw OTG Nofity Host Driver remove\n");
flag = 1;
break;
case MID_OTG_NOTIFY_CLIENTADD:
dev_dbg(lnw->dev, "Lnw OTG Nofity Client Driver Add\n");
flag = 1;
break;
case MID_OTG_NOTIFY_CLIENTREMOVE:
dev_dbg(lnw->dev, "Lnw OTG Nofity Client Driver remove\n");
flag = 1;
break;
default:
dev_dbg(lnw->dev, "Lnw OTG Nofity unknown notify message\n");
return NOTIFY_DONE;
}
if (flag)
langwell_update_transceiver();
return NOTIFY_OK;
}
static void langwell_otg_work(struct work_struct *work)
{
struct langwell_otg *lnw;
struct intel_mid_otg_xceiv *iotg;
int retval;
struct pci_dev *pdev;
lnw = container_of(work, struct langwell_otg, work);
iotg = &lnw->iotg;
pdev = to_pci_dev(lnw->dev);
dev_dbg(lnw->dev, "%s: old state = %s\n", __func__,
otg_state_string(iotg->otg.state));
switch (iotg->otg.state) {
case OTG_STATE_UNDEFINED:
case OTG_STATE_B_IDLE:
if (!iotg->hsm.id) {
langwell_otg_del_timer(b_srp_init_tmr);
del_timer_sync(&lnw->hsm_timer);
iotg->otg.default_a = 1;
iotg->hsm.a_srp_det = 0;
langwell_otg_chrg_vbus(0);
set_host_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_A_IDLE;
langwell_update_transceiver();
} else if (iotg->hsm.b_sess_vld) {
langwell_otg_del_timer(b_srp_init_tmr);
del_timer_sync(&lnw->hsm_timer);
iotg->hsm.b_sess_end = 0;
iotg->hsm.a_bus_suspend = 0;
langwell_otg_chrg_vbus(0);
if (lnw->iotg.start_peripheral) {
lnw->iotg.start_peripheral(&lnw->iotg);
iotg->otg.state = OTG_STATE_B_PERIPHERAL;
} else
dev_dbg(lnw->dev, "client driver not loaded\n");
} else if (iotg->hsm.b_srp_init_tmout) {
iotg->hsm.b_srp_init_tmout = 0;
dev_warn(lnw->dev, "SRP init timeout\n");
} else if (iotg->hsm.b_srp_fail_tmout) {
iotg->hsm.b_srp_fail_tmout = 0;
iotg->hsm.b_bus_req = 0;
/* No silence failure */
langwell_otg_nsf_msg(6);
} else if (iotg->hsm.b_bus_req && iotg->hsm.b_sess_end) {
del_timer_sync(&lnw->hsm_timer);
/* workaround for b_se0_srp detection */
retval = langwell_otg_check_se0_srp(0);
if (retval) {
iotg->hsm.b_bus_req = 0;
dev_dbg(lnw->dev, "LS isn't SE0, try later\n");
} else {
/* clear the PHCD before start srp */
langwell_otg_phy_low_power(0);
/* Start SRP */
langwell_otg_add_timer(b_srp_init_tmr);
iotg->otg.start_srp(&iotg->otg);
langwell_otg_del_timer(b_srp_init_tmr);
langwell_otg_add_ktimer(TB_SRP_FAIL_TMR);
/* reset PHY low power mode here */
langwell_otg_phy_low_power_wait(1);
}
}
break;
case OTG_STATE_B_SRP_INIT:
if (!iotg->hsm.id) {
iotg->otg.default_a = 1;
iotg->hsm.a_srp_det = 0;
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
langwell_otg_chrg_vbus(0);
set_host_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_A_IDLE;
langwell_update_transceiver();
} else if (iotg->hsm.b_sess_vld) {
langwell_otg_chrg_vbus(0);
if (lnw->iotg.start_peripheral) {
lnw->iotg.start_peripheral(&lnw->iotg);
iotg->otg.state = OTG_STATE_B_PERIPHERAL;
} else
dev_dbg(lnw->dev, "client driver not loaded\n");
}
break;
case OTG_STATE_B_PERIPHERAL:
if (!iotg->hsm.id) {
iotg->otg.default_a = 1;
iotg->hsm.a_srp_det = 0;
langwell_otg_chrg_vbus(0);
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
set_host_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_A_IDLE;
langwell_update_transceiver();
} else if (!iotg->hsm.b_sess_vld) {
iotg->hsm.b_hnp_enable = 0;
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
iotg->otg.state = OTG_STATE_B_IDLE;
} else if (iotg->hsm.b_bus_req && iotg->otg.gadget &&
iotg->otg.gadget->b_hnp_enable &&
iotg->hsm.a_bus_suspend) {
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
langwell_otg_HAAR(1);
iotg->hsm.a_conn = 0;
if (lnw->iotg.start_host) {
lnw->iotg.start_host(&lnw->iotg);
iotg->otg.state = OTG_STATE_B_WAIT_ACON;
} else
dev_dbg(lnw->dev,
"host driver not loaded.\n");
iotg->hsm.a_bus_resume = 0;
langwell_otg_add_ktimer(TB_ASE0_BRST_TMR);
}
break;
case OTG_STATE_B_WAIT_ACON:
if (!iotg->hsm.id) {
/* delete hsm timer for b_ase0_brst_tmr */
del_timer_sync(&lnw->hsm_timer);
iotg->otg.default_a = 1;
iotg->hsm.a_srp_det = 0;
langwell_otg_chrg_vbus(0);
langwell_otg_HAAR(0);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
set_host_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_A_IDLE;
langwell_update_transceiver();
} else if (!iotg->hsm.b_sess_vld) {
/* delete hsm timer for b_ase0_brst_tmr */
del_timer_sync(&lnw->hsm_timer);
iotg->hsm.b_hnp_enable = 0;
iotg->hsm.b_bus_req = 0;
langwell_otg_chrg_vbus(0);
langwell_otg_HAAR(0);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
set_client_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_B_IDLE;
} else if (iotg->hsm.a_conn) {
/* delete hsm timer for b_ase0_brst_tmr */
del_timer_sync(&lnw->hsm_timer);
langwell_otg_HAAR(0);
iotg->otg.state = OTG_STATE_B_HOST;
langwell_update_transceiver();
} else if (iotg->hsm.a_bus_resume ||
iotg->hsm.b_ase0_brst_tmout) {
/* delete hsm timer for b_ase0_brst_tmr */
del_timer_sync(&lnw->hsm_timer);
langwell_otg_HAAR(0);
langwell_otg_nsf_msg(7);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
iotg->hsm.a_bus_suspend = 0;
iotg->hsm.b_bus_req = 0;
if (lnw->iotg.start_peripheral)
lnw->iotg.start_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver not loaded.\n");
iotg->otg.state = OTG_STATE_B_PERIPHERAL;
}
break;
case OTG_STATE_B_HOST:
if (!iotg->hsm.id) {
iotg->otg.default_a = 1;
iotg->hsm.a_srp_det = 0;
langwell_otg_chrg_vbus(0);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
set_host_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_A_IDLE;
langwell_update_transceiver();
} else if (!iotg->hsm.b_sess_vld) {
iotg->hsm.b_hnp_enable = 0;
iotg->hsm.b_bus_req = 0;
langwell_otg_chrg_vbus(0);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
set_client_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_B_IDLE;
} else if ((!iotg->hsm.b_bus_req) ||
(!iotg->hsm.a_conn)) {
iotg->hsm.b_bus_req = 0;
langwell_otg_loc_sof(0);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
iotg->hsm.a_bus_suspend = 0;
if (lnw->iotg.start_peripheral)
lnw->iotg.start_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver not loaded.\n");
iotg->otg.state = OTG_STATE_B_PERIPHERAL;
}
break;
case OTG_STATE_A_IDLE:
iotg->otg.default_a = 1;
if (iotg->hsm.id) {
iotg->otg.default_a = 0;
iotg->hsm.b_bus_req = 0;
iotg->hsm.vbus_srp_up = 0;
langwell_otg_chrg_vbus(0);
set_client_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_B_IDLE;
langwell_update_transceiver();
} else if (!iotg->hsm.a_bus_drop &&
(iotg->hsm.a_srp_det || iotg->hsm.a_bus_req)) {
langwell_otg_phy_low_power(0);
/* Turn on VBus */
iotg->otg.set_vbus(&iotg->otg, true);
iotg->hsm.vbus_srp_up = 0;
iotg->hsm.a_wait_vrise_tmout = 0;
langwell_otg_add_timer(a_wait_vrise_tmr);
iotg->otg.state = OTG_STATE_A_WAIT_VRISE;
langwell_update_transceiver();
} else if (!iotg->hsm.a_bus_drop && iotg->hsm.a_sess_vld) {
iotg->hsm.vbus_srp_up = 1;
} else if (!iotg->hsm.a_sess_vld && iotg->hsm.vbus_srp_up) {
msleep(10);
langwell_otg_phy_low_power(0);
/* Turn on VBus */
iotg->otg.set_vbus(&iotg->otg, true);
iotg->hsm.a_srp_det = 1;
iotg->hsm.vbus_srp_up = 0;
iotg->hsm.a_wait_vrise_tmout = 0;
langwell_otg_add_timer(a_wait_vrise_tmr);
iotg->otg.state = OTG_STATE_A_WAIT_VRISE;
langwell_update_transceiver();
} else if (!iotg->hsm.a_sess_vld &&
!iotg->hsm.vbus_srp_up) {
langwell_otg_phy_low_power(1);
}
break;
case OTG_STATE_A_WAIT_VRISE:
if (iotg->hsm.id) {
langwell_otg_del_timer(a_wait_vrise_tmr);
iotg->hsm.b_bus_req = 0;
iotg->otg.default_a = 0;
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
set_client_mode();
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_B_IDLE;
} else if (iotg->hsm.a_vbus_vld) {
langwell_otg_del_timer(a_wait_vrise_tmr);
iotg->hsm.b_conn = 0;
if (lnw->iotg.start_host)
lnw->iotg.start_host(&lnw->iotg);
else {
dev_dbg(lnw->dev, "host driver not loaded.\n");
break;
}
langwell_otg_add_ktimer(TA_WAIT_BCON_TMR);
iotg->otg.state = OTG_STATE_A_WAIT_BCON;
} else if (iotg->hsm.a_wait_vrise_tmout) {
iotg->hsm.b_conn = 0;
if (iotg->hsm.a_vbus_vld) {
if (lnw->iotg.start_host)
lnw->iotg.start_host(&lnw->iotg);
else {
dev_dbg(lnw->dev,
"host driver not loaded.\n");
break;
}
langwell_otg_add_ktimer(TA_WAIT_BCON_TMR);
iotg->otg.state = OTG_STATE_A_WAIT_BCON;
} else {
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_A_VBUS_ERR;
}
}
break;
case OTG_STATE_A_WAIT_BCON:
if (iotg->hsm.id) {
/* delete hsm timer for a_wait_bcon_tmr */
del_timer_sync(&lnw->hsm_timer);
iotg->otg.default_a = 0;
iotg->hsm.b_bus_req = 0;
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
set_client_mode();
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_B_IDLE;
langwell_update_transceiver();
} else if (!iotg->hsm.a_vbus_vld) {
/* delete hsm timer for a_wait_bcon_tmr */
del_timer_sync(&lnw->hsm_timer);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_A_VBUS_ERR;
} else if (iotg->hsm.a_bus_drop ||
(iotg->hsm.a_wait_bcon_tmout &&
!iotg->hsm.a_bus_req)) {
/* delete hsm timer for a_wait_bcon_tmr */
del_timer_sync(&lnw->hsm_timer);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
} else if (iotg->hsm.b_conn) {
/* delete hsm timer for a_wait_bcon_tmr */
del_timer_sync(&lnw->hsm_timer);
iotg->hsm.a_suspend_req = 0;
iotg->otg.state = OTG_STATE_A_HOST;
if (iotg->hsm.a_srp_det && iotg->otg.host &&
!iotg->otg.host->b_hnp_enable) {
/* SRP capable peripheral-only device */
iotg->hsm.a_bus_req = 1;
iotg->hsm.a_srp_det = 0;
} else if (!iotg->hsm.a_bus_req && iotg->otg.host &&
iotg->otg.host->b_hnp_enable) {
/* It is not safe enough to do a fast
* transition from A_WAIT_BCON to
* A_SUSPEND */
msleep(10000);
if (iotg->hsm.a_bus_req)
break;
if (request_irq(pdev->irq,
otg_dummy_irq, IRQF_SHARED,
driver_name, iotg->base) != 0) {
dev_dbg(lnw->dev,
"request interrupt %d fail\n",
pdev->irq);
}
langwell_otg_HABA(1);
iotg->hsm.b_bus_resume = 0;
iotg->hsm.a_aidl_bdis_tmout = 0;
langwell_otg_loc_sof(0);
/* clear PHCD to enable HW timer */
langwell_otg_phy_low_power(0);
langwell_otg_add_timer(a_aidl_bdis_tmr);
iotg->otg.state = OTG_STATE_A_SUSPEND;
} else if (!iotg->hsm.a_bus_req && iotg->otg.host &&
!iotg->otg.host->b_hnp_enable) {
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
}
}
break;
case OTG_STATE_A_HOST:
if (iotg->hsm.id) {
iotg->otg.default_a = 0;
iotg->hsm.b_bus_req = 0;
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
set_client_mode();
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_B_IDLE;
langwell_update_transceiver();
} else if (iotg->hsm.a_bus_drop ||
(iotg->otg.host &&
!iotg->otg.host->b_hnp_enable &&
!iotg->hsm.a_bus_req)) {
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
} else if (!iotg->hsm.a_vbus_vld) {
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_A_VBUS_ERR;
} else if (iotg->otg.host &&
iotg->otg.host->b_hnp_enable &&
!iotg->hsm.a_bus_req) {
/* Set HABA to enable hardware assistance to signal
* A-connect after receiver B-disconnect. Hardware
* will then set client mode and enable URE, SLE and
* PCE after the assistance. otg_dummy_irq is used to
* clean these ints when client driver is not resumed.
*/
if (request_irq(pdev->irq, otg_dummy_irq, IRQF_SHARED,
driver_name, iotg->base) != 0) {
dev_dbg(lnw->dev,
"request interrupt %d failed\n",
pdev->irq);
}
/* set HABA */
langwell_otg_HABA(1);
iotg->hsm.b_bus_resume = 0;
iotg->hsm.a_aidl_bdis_tmout = 0;
langwell_otg_loc_sof(0);
/* clear PHCD to enable HW timer */
langwell_otg_phy_low_power(0);
langwell_otg_add_timer(a_aidl_bdis_tmr);
iotg->otg.state = OTG_STATE_A_SUSPEND;
} else if (!iotg->hsm.b_conn || !iotg->hsm.a_bus_req) {
langwell_otg_add_ktimer(TA_WAIT_BCON_TMR);
iotg->otg.state = OTG_STATE_A_WAIT_BCON;
}
break;
case OTG_STATE_A_SUSPEND:
if (iotg->hsm.id) {
langwell_otg_del_timer(a_aidl_bdis_tmr);
langwell_otg_HABA(0);
free_irq(pdev->irq, iotg->base);
iotg->otg.default_a = 0;
iotg->hsm.b_bus_req = 0;
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
set_client_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_B_IDLE;
langwell_update_transceiver();
} else if (iotg->hsm.a_bus_req ||
iotg->hsm.b_bus_resume) {
langwell_otg_del_timer(a_aidl_bdis_tmr);
langwell_otg_HABA(0);
free_irq(pdev->irq, iotg->base);
iotg->hsm.a_suspend_req = 0;
langwell_otg_loc_sof(1);
iotg->otg.state = OTG_STATE_A_HOST;
} else if (iotg->hsm.a_aidl_bdis_tmout ||
iotg->hsm.a_bus_drop) {
langwell_otg_del_timer(a_aidl_bdis_tmr);
langwell_otg_HABA(0);
free_irq(pdev->irq, iotg->base);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
} else if (!iotg->hsm.b_conn && iotg->otg.host &&
iotg->otg.host->b_hnp_enable) {
langwell_otg_del_timer(a_aidl_bdis_tmr);
langwell_otg_HABA(0);
free_irq(pdev->irq, iotg->base);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
iotg->hsm.b_bus_suspend = 0;
iotg->hsm.b_bus_suspend_vld = 0;
/* msleep(200); */
if (lnw->iotg.start_peripheral)
lnw->iotg.start_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver not loaded.\n");
langwell_otg_add_ktimer(TB_BUS_SUSPEND_TMR);
iotg->otg.state = OTG_STATE_A_PERIPHERAL;
break;
} else if (!iotg->hsm.a_vbus_vld) {
langwell_otg_del_timer(a_aidl_bdis_tmr);
langwell_otg_HABA(0);
free_irq(pdev->irq, iotg->base);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_A_VBUS_ERR;
}
break;
case OTG_STATE_A_PERIPHERAL:
if (iotg->hsm.id) {
/* delete hsm timer for b_bus_suspend_tmr */
del_timer_sync(&lnw->hsm_timer);
iotg->otg.default_a = 0;
iotg->hsm.b_bus_req = 0;
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
set_client_mode();
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_B_IDLE;
langwell_update_transceiver();
} else if (!iotg->hsm.a_vbus_vld) {
/* delete hsm timer for b_bus_suspend_tmr */
del_timer_sync(&lnw->hsm_timer);
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
langwell_otg_phy_low_power_wait(1);
iotg->otg.state = OTG_STATE_A_VBUS_ERR;
} else if (iotg->hsm.a_bus_drop) {
/* delete hsm timer for b_bus_suspend_tmr */
del_timer_sync(&lnw->hsm_timer);
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
} else if (iotg->hsm.b_bus_suspend) {
/* delete hsm timer for b_bus_suspend_tmr */
del_timer_sync(&lnw->hsm_timer);
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
if (lnw->iotg.start_host)
lnw->iotg.start_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver not loaded.\n");
langwell_otg_add_ktimer(TA_WAIT_BCON_TMR);
iotg->otg.state = OTG_STATE_A_WAIT_BCON;
} else if (iotg->hsm.b_bus_suspend_tmout) {
u32 val;
val = readl(lnw->iotg.base + CI_PORTSC1);
if (!(val & PORTSC_SUSP))
break;
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(lnw->dev,
"client driver has been removed.\n");
if (lnw->iotg.start_host)
lnw->iotg.start_host(&lnw->iotg);
else
dev_dbg(lnw->dev,
"host driver not loaded.\n");
langwell_otg_add_ktimer(TA_WAIT_BCON_TMR);
iotg->otg.state = OTG_STATE_A_WAIT_BCON;
}
break;
case OTG_STATE_A_VBUS_ERR:
if (iotg->hsm.id) {
iotg->otg.default_a = 0;
iotg->hsm.a_clr_err = 0;
iotg->hsm.a_srp_det = 0;
set_client_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_B_IDLE;
langwell_update_transceiver();
} else if (iotg->hsm.a_clr_err) {
iotg->hsm.a_clr_err = 0;
iotg->hsm.a_srp_det = 0;
reset_otg();
init_hsm();
if (iotg->otg.state == OTG_STATE_A_IDLE)
langwell_update_transceiver();
} else {
/* FW will clear PHCD bit when any VBus
* event detected. Reset PHCD to 1 again */
langwell_otg_phy_low_power(1);
}
break;
case OTG_STATE_A_WAIT_VFALL:
if (iotg->hsm.id) {
iotg->otg.default_a = 0;
set_client_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_B_IDLE;
langwell_update_transceiver();
} else if (iotg->hsm.a_bus_req) {
/* Turn on VBus */
iotg->otg.set_vbus(&iotg->otg, true);
iotg->hsm.a_wait_vrise_tmout = 0;
langwell_otg_add_timer(a_wait_vrise_tmr);
iotg->otg.state = OTG_STATE_A_WAIT_VRISE;
} else if (!iotg->hsm.a_sess_vld) {
iotg->hsm.a_srp_det = 0;
set_host_mode();
langwell_otg_phy_low_power(1);
iotg->otg.state = OTG_STATE_A_IDLE;
}
break;
default:
;
}
dev_dbg(lnw->dev, "%s: new state = %s\n", __func__,
otg_state_string(iotg->otg.state));
}
static ssize_t
show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
{
struct langwell_otg *lnw = the_transceiver;
char *next;
unsigned size, t;
next = buf;
size = PAGE_SIZE;
t = scnprintf(next, size,
"\n"
"USBCMD = 0x%08x\n"
"USBSTS = 0x%08x\n"
"USBINTR = 0x%08x\n"
"ASYNCLISTADDR = 0x%08x\n"
"PORTSC1 = 0x%08x\n"
"HOSTPC1 = 0x%08x\n"
"OTGSC = 0x%08x\n"
"USBMODE = 0x%08x\n",
readl(lnw->iotg.base + 0x30),
readl(lnw->iotg.base + 0x34),
readl(lnw->iotg.base + 0x38),
readl(lnw->iotg.base + 0x48),
readl(lnw->iotg.base + 0x74),
readl(lnw->iotg.base + 0xb4),
readl(lnw->iotg.base + 0xf4),
readl(lnw->iotg.base + 0xf8)
);
size -= t;
next += t;
return PAGE_SIZE - size;
}
static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
static ssize_t
show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
char *next;
unsigned size, t;
next = buf;
size = PAGE_SIZE;
if (iotg->otg.host)
iotg->hsm.a_set_b_hnp_en = iotg->otg.host->b_hnp_enable;
if (iotg->otg.gadget)
iotg->hsm.b_hnp_enable = iotg->otg.gadget->b_hnp_enable;
t = scnprintf(next, size,
"\n"
"current state = %s\n"
"a_bus_resume = \t%d\n"
"a_bus_suspend = \t%d\n"
"a_conn = \t%d\n"
"a_sess_vld = \t%d\n"
"a_srp_det = \t%d\n"
"a_vbus_vld = \t%d\n"
"b_bus_resume = \t%d\n"
"b_bus_suspend = \t%d\n"
"b_conn = \t%d\n"
"b_se0_srp = \t%d\n"
"b_sess_end = \t%d\n"
"b_sess_vld = \t%d\n"
"id = \t%d\n"
"a_set_b_hnp_en = \t%d\n"
"b_srp_done = \t%d\n"
"b_hnp_enable = \t%d\n"
"a_wait_vrise_tmout = \t%d\n"
"a_wait_bcon_tmout = \t%d\n"
"a_aidl_bdis_tmout = \t%d\n"
"b_ase0_brst_tmout = \t%d\n"
"a_bus_drop = \t%d\n"
"a_bus_req = \t%d\n"
"a_clr_err = \t%d\n"
"a_suspend_req = \t%d\n"
"b_bus_req = \t%d\n"
"b_bus_suspend_tmout = \t%d\n"
"b_bus_suspend_vld = \t%d\n",
otg_state_string(iotg->otg.state),
iotg->hsm.a_bus_resume,
iotg->hsm.a_bus_suspend,
iotg->hsm.a_conn,
iotg->hsm.a_sess_vld,
iotg->hsm.a_srp_det,
iotg->hsm.a_vbus_vld,
iotg->hsm.b_bus_resume,
iotg->hsm.b_bus_suspend,
iotg->hsm.b_conn,
iotg->hsm.b_se0_srp,
iotg->hsm.b_sess_end,
iotg->hsm.b_sess_vld,
iotg->hsm.id,
iotg->hsm.a_set_b_hnp_en,
iotg->hsm.b_srp_done,
iotg->hsm.b_hnp_enable,
iotg->hsm.a_wait_vrise_tmout,
iotg->hsm.a_wait_bcon_tmout,
iotg->hsm.a_aidl_bdis_tmout,
iotg->hsm.b_ase0_brst_tmout,
iotg->hsm.a_bus_drop,
iotg->hsm.a_bus_req,
iotg->hsm.a_clr_err,
iotg->hsm.a_suspend_req,
iotg->hsm.b_bus_req,
iotg->hsm.b_bus_suspend_tmout,
iotg->hsm.b_bus_suspend_vld
);
size -= t;
next += t;
return PAGE_SIZE - size;
}
static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL);
static ssize_t
get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
{
struct langwell_otg *lnw = the_transceiver;
char *next;
unsigned size, t;
next = buf;
size = PAGE_SIZE;
t = scnprintf(next, size, "%d", lnw->iotg.hsm.a_bus_req);
size -= t;
next += t;
return PAGE_SIZE - size;
}
static ssize_t
set_a_bus_req(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
if (!iotg->otg.default_a)
return -1;
if (count > 2)
return -1;
if (buf[0] == '0') {
iotg->hsm.a_bus_req = 0;
dev_dbg(lnw->dev, "User request: a_bus_req = 0\n");
} else if (buf[0] == '1') {
/* If a_bus_drop is TRUE, a_bus_req can't be set */
if (iotg->hsm.a_bus_drop)
return -1;
iotg->hsm.a_bus_req = 1;
dev_dbg(lnw->dev, "User request: a_bus_req = 1\n");
}
if (spin_trylock(&lnw->wq_lock)) {
langwell_update_transceiver();
spin_unlock(&lnw->wq_lock);
}
return count;
}
static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req);
static ssize_t
get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
{
struct langwell_otg *lnw = the_transceiver;
char *next;
unsigned size, t;
next = buf;
size = PAGE_SIZE;
t = scnprintf(next, size, "%d", lnw->iotg.hsm.a_bus_drop);
size -= t;
next += t;
return PAGE_SIZE - size;
}
static ssize_t
set_a_bus_drop(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
if (!iotg->otg.default_a)
return -1;
if (count > 2)
return -1;
if (buf[0] == '0') {
iotg->hsm.a_bus_drop = 0;
dev_dbg(lnw->dev, "User request: a_bus_drop = 0\n");
} else if (buf[0] == '1') {
iotg->hsm.a_bus_drop = 1;
iotg->hsm.a_bus_req = 0;
dev_dbg(lnw->dev, "User request: a_bus_drop = 1\n");
dev_dbg(lnw->dev, "User request: and a_bus_req = 0\n");
}
if (spin_trylock(&lnw->wq_lock)) {
langwell_update_transceiver();
spin_unlock(&lnw->wq_lock);
}
return count;
}
static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, set_a_bus_drop);
static ssize_t
get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
{
struct langwell_otg *lnw = the_transceiver;
char *next;
unsigned size, t;
next = buf;
size = PAGE_SIZE;
t = scnprintf(next, size, "%d", lnw->iotg.hsm.b_bus_req);
size -= t;
next += t;
return PAGE_SIZE - size;
}
static ssize_t
set_b_bus_req(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
if (iotg->otg.default_a)
return -1;
if (count > 2)
return -1;
if (buf[0] == '0') {
iotg->hsm.b_bus_req = 0;
dev_dbg(lnw->dev, "User request: b_bus_req = 0\n");
} else if (buf[0] == '1') {
iotg->hsm.b_bus_req = 1;
dev_dbg(lnw->dev, "User request: b_bus_req = 1\n");
}
if (spin_trylock(&lnw->wq_lock)) {
langwell_update_transceiver();
spin_unlock(&lnw->wq_lock);
}
return count;
}
static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req);
static ssize_t
set_a_clr_err(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
if (!iotg->otg.default_a)
return -1;
if (count > 2)
return -1;
if (buf[0] == '1') {
iotg->hsm.a_clr_err = 1;
dev_dbg(lnw->dev, "User request: a_clr_err = 1\n");
}
if (spin_trylock(&lnw->wq_lock)) {
langwell_update_transceiver();
spin_unlock(&lnw->wq_lock);
}
return count;
}
static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
static struct attribute *inputs_attrs[] = {
&dev_attr_a_bus_req.attr,
&dev_attr_a_bus_drop.attr,
&dev_attr_b_bus_req.attr,
&dev_attr_a_clr_err.attr,
NULL,
};
static struct attribute_group debug_dev_attr_group = {
.name = "inputs",
.attrs = inputs_attrs,
};
static int langwell_otg_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
unsigned long resource, len;
void __iomem *base = NULL;
int retval;
u32 val32;
struct langwell_otg *lnw;
char qname[] = "langwell_otg_queue";
retval = 0;
dev_dbg(&pdev->dev, "\notg controller is detected.\n");
if (pci_enable_device(pdev) < 0) {
retval = -ENODEV;
goto done;
}
lnw = kzalloc(sizeof *lnw, GFP_KERNEL);
if (lnw == NULL) {
retval = -ENOMEM;
goto done;
}
the_transceiver = lnw;
/* control register: BAR 0 */
resource = pci_resource_start(pdev, 0);
len = pci_resource_len(pdev, 0);
if (!request_mem_region(resource, len, driver_name)) {
retval = -EBUSY;
goto err;
}
lnw->region = 1;
base = ioremap_nocache(resource, len);
if (base == NULL) {
retval = -EFAULT;
goto err;
}
lnw->iotg.base = base;
if (!request_mem_region(USBCFG_ADDR, USBCFG_LEN, driver_name)) {
retval = -EBUSY;
goto err;
}
lnw->cfg_region = 1;
/* For the SCCB.USBCFG register */
base = ioremap_nocache(USBCFG_ADDR, USBCFG_LEN);
if (base == NULL) {
retval = -EFAULT;
goto err;
}
lnw->usbcfg = base;
if (!pdev->irq) {
dev_dbg(&pdev->dev, "No IRQ.\n");
retval = -ENODEV;
goto err;
}
lnw->qwork = create_singlethread_workqueue(qname);
if (!lnw->qwork) {
dev_dbg(&pdev->dev, "cannot create workqueue %s\n", qname);
retval = -ENOMEM;
goto err;
}
INIT_WORK(&lnw->work, langwell_otg_work);
/* OTG common part */
lnw->dev = &pdev->dev;
lnw->iotg.otg.dev = lnw->dev;
lnw->iotg.otg.label = driver_name;
lnw->iotg.otg.set_host = langwell_otg_set_host;
lnw->iotg.otg.set_peripheral = langwell_otg_set_peripheral;
lnw->iotg.otg.set_power = langwell_otg_set_power;
lnw->iotg.otg.set_vbus = langwell_otg_set_vbus;
lnw->iotg.otg.start_srp = langwell_otg_start_srp;
lnw->iotg.otg.state = OTG_STATE_UNDEFINED;
if (otg_set_transceiver(&lnw->iotg.otg)) {
dev_dbg(lnw->dev, "can't set transceiver\n");
retval = -EBUSY;
goto err;
}
reset_otg();
init_hsm();
spin_lock_init(&lnw->lock);
spin_lock_init(&lnw->wq_lock);
INIT_LIST_HEAD(&active_timers);
retval = langwell_otg_init_timers(&lnw->iotg.hsm);
if (retval) {
dev_dbg(&pdev->dev, "Failed to init timers\n");
goto err;
}
init_timer(&lnw->hsm_timer);
ATOMIC_INIT_NOTIFIER_HEAD(&lnw->iotg.iotg_notifier);
lnw->iotg_notifier.notifier_call = langwell_otg_iotg_notify;
retval = intel_mid_otg_register_notifier(&lnw->iotg,
&lnw->iotg_notifier);
if (retval) {
dev_dbg(lnw->dev, "Failed to register notifier\n");
goto err;
}
if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
driver_name, lnw) != 0) {
dev_dbg(lnw->dev, "request interrupt %d failed\n", pdev->irq);
retval = -EBUSY;
goto err;
}
/* enable OTGSC int */
val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE |
OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU;
writel(val32, lnw->iotg.base + CI_OTGSC);
retval = device_create_file(&pdev->dev, &dev_attr_registers);
if (retval < 0) {
dev_dbg(lnw->dev,
"Can't register sysfs attribute: %d\n", retval);
goto err;
}
retval = device_create_file(&pdev->dev, &dev_attr_hsm);
if (retval < 0) {
dev_dbg(lnw->dev, "Can't hsm sysfs attribute: %d\n", retval);
goto err;
}
retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group);
if (retval < 0) {
dev_dbg(lnw->dev,
"Can't register sysfs attr group: %d\n", retval);
goto err;
}
if (lnw->iotg.otg.state == OTG_STATE_A_IDLE)
langwell_update_transceiver();
return 0;
err:
if (the_transceiver)
langwell_otg_remove(pdev);
done:
return retval;
}
static void langwell_otg_remove(struct pci_dev *pdev)
{
struct langwell_otg *lnw = the_transceiver;
if (lnw->qwork) {
flush_workqueue(lnw->qwork);
destroy_workqueue(lnw->qwork);
}
intel_mid_otg_unregister_notifier(&lnw->iotg, &lnw->iotg_notifier);
langwell_otg_free_timers();
/* disable OTGSC interrupt as OTGSC doesn't change in reset */
writel(0, lnw->iotg.base + CI_OTGSC);
if (pdev->irq)
free_irq(pdev->irq, lnw);
if (lnw->usbcfg)
iounmap(lnw->usbcfg);
if (lnw->cfg_region)
release_mem_region(USBCFG_ADDR, USBCFG_LEN);
if (lnw->iotg.base)
iounmap(lnw->iotg.base);
if (lnw->region)
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
otg_set_transceiver(NULL);
pci_disable_device(pdev);
sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group);
device_remove_file(&pdev->dev, &dev_attr_hsm);
device_remove_file(&pdev->dev, &dev_attr_registers);
kfree(lnw);
lnw = NULL;
}
static void transceiver_suspend(struct pci_dev *pdev)
{
pci_save_state(pdev);
pci_set_power_state(pdev, PCI_D3hot);
langwell_otg_phy_low_power(1);
}
static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
{
struct langwell_otg *lnw = the_transceiver;
struct intel_mid_otg_xceiv *iotg = &lnw->iotg;
int ret = 0;
/* Disbale OTG interrupts */
langwell_otg_intr(0);
if (pdev->irq)
free_irq(pdev->irq, lnw);
/* Prevent more otg_work */
flush_workqueue(lnw->qwork);
destroy_workqueue(lnw->qwork);
lnw->qwork = NULL;
/* start actions */
switch (iotg->otg.state) {
case OTG_STATE_A_WAIT_VFALL:
iotg->otg.state = OTG_STATE_A_IDLE;
case OTG_STATE_A_IDLE:
case OTG_STATE_B_IDLE:
case OTG_STATE_A_VBUS_ERR:
transceiver_suspend(pdev);
break;
case OTG_STATE_A_WAIT_VRISE:
langwell_otg_del_timer(a_wait_vrise_tmr);
iotg->hsm.a_srp_det = 0;
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_IDLE;
transceiver_suspend(pdev);
break;
case OTG_STATE_A_WAIT_BCON:
del_timer_sync(&lnw->hsm_timer);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(&pdev->dev, "host driver has been removed.\n");
iotg->hsm.a_srp_det = 0;
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_IDLE;
transceiver_suspend(pdev);
break;
case OTG_STATE_A_HOST:
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(&pdev->dev, "host driver has been removed.\n");
iotg->hsm.a_srp_det = 0;
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_IDLE;
transceiver_suspend(pdev);
break;
case OTG_STATE_A_SUSPEND:
langwell_otg_del_timer(a_aidl_bdis_tmr);
langwell_otg_HABA(0);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(lnw->dev, "host driver has been removed.\n");
iotg->hsm.a_srp_det = 0;
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_IDLE;
transceiver_suspend(pdev);
break;
case OTG_STATE_A_PERIPHERAL:
del_timer_sync(&lnw->hsm_timer);
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(&pdev->dev,
"client driver has been removed.\n");
iotg->hsm.a_srp_det = 0;
/* Turn off VBus */
iotg->otg.set_vbus(&iotg->otg, false);
iotg->otg.state = OTG_STATE_A_IDLE;
transceiver_suspend(pdev);
break;
case OTG_STATE_B_HOST:
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(&pdev->dev, "host driver has been removed.\n");
iotg->hsm.b_bus_req = 0;
iotg->otg.state = OTG_STATE_B_IDLE;
transceiver_suspend(pdev);
break;
case OTG_STATE_B_PERIPHERAL:
if (lnw->iotg.stop_peripheral)
lnw->iotg.stop_peripheral(&lnw->iotg);
else
dev_dbg(&pdev->dev,
"client driver has been removed.\n");
iotg->otg.state = OTG_STATE_B_IDLE;
transceiver_suspend(pdev);
break;
case OTG_STATE_B_WAIT_ACON:
/* delete hsm timer for b_ase0_brst_tmr */
del_timer_sync(&lnw->hsm_timer);
langwell_otg_HAAR(0);
if (lnw->iotg.stop_host)
lnw->iotg.stop_host(&lnw->iotg);
else
dev_dbg(&pdev->dev, "host driver has been removed.\n");
iotg->hsm.b_bus_req = 0;
iotg->otg.state = OTG_STATE_B_IDLE;
transceiver_suspend(pdev);
break;
default:
dev_dbg(lnw->dev, "error state before suspend\n");
break;
}
return ret;
}
static void transceiver_resume(struct pci_dev *pdev)
{
pci_restore_state(pdev);
pci_set_power_state(pdev, PCI_D0);
}
static int langwell_otg_resume(struct pci_dev *pdev)
{
struct langwell_otg *lnw = the_transceiver;
int ret = 0;
transceiver_resume(pdev);
lnw->qwork = create_singlethread_workqueue("langwell_otg_queue");
if (!lnw->qwork) {
dev_dbg(&pdev->dev, "cannot create langwell otg workqueuen");
ret = -ENOMEM;
goto error;
}
if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
driver_name, lnw) != 0) {
dev_dbg(&pdev->dev, "request interrupt %d failed\n", pdev->irq);
ret = -EBUSY;
goto error;
}
/* enable OTG interrupts */
langwell_otg_intr(1);
update_hsm();
langwell_update_transceiver();
return ret;
error:
langwell_otg_intr(0);
transceiver_suspend(pdev);
return ret;
}
static int __init langwell_otg_init(void)
{
return pci_register_driver(&otg_pci_driver);
}
module_init(langwell_otg_init);
static void __exit langwell_otg_cleanup(void)
{
pci_unregister_driver(&otg_pci_driver);
}
module_exit(langwell_otg_cleanup);
......@@ -202,6 +202,7 @@ static void mv_otg_init_irq(struct mv_otg *mvotg)
static void mv_otg_start_host(struct mv_otg *mvotg, int on)
{
#ifdef CONFIG_USB
struct otg_transceiver *otg = &mvotg->otg;
struct usb_hcd *hcd;
......@@ -216,6 +217,7 @@ static void mv_otg_start_host(struct mv_otg *mvotg, int on)
usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
else
usb_remove_hcd(hcd);
#endif /* CONFIG_USB */
}
static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
......
......@@ -425,7 +425,7 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv,
struct usbhs_pipe *pipe;
int recip = ctrl->bRequestType & USB_RECIP_MASK;
int nth = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK;
int ret;
int ret = 0;
int (*func)(struct usbhs_priv *priv, struct usbhsg_uep *uep,
struct usb_ctrlrequest *ctrl);
char *msg;
......
......@@ -39,6 +39,8 @@ static void cp210x_get_termios(struct tty_struct *,
struct usb_serial_port *port);
static void cp210x_get_termios_port(struct usb_serial_port *port,
unsigned int *cflagp, unsigned int *baudp);
static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
struct ktermios *);
static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
struct ktermios*);
static int cp210x_tiocmget(struct tty_struct *);
......@@ -138,6 +140,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
{ } /* Terminating Entry */
};
......@@ -201,6 +204,8 @@ static struct usb_serial_driver cp210x_device = {
#define CP210X_EMBED_EVENTS 0x15
#define CP210X_GET_EVENTSTATE 0x16
#define CP210X_SET_CHARS 0x19
#define CP210X_GET_BAUDRATE 0x1D
#define CP210X_SET_BAUDRATE 0x1E
/* CP210X_IFC_ENABLE */
#define UART_ENABLE 0x0001
......@@ -360,8 +365,8 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,
* Quantises the baud rate as per AN205 Table 1
*/
static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
if (baud <= 56) baud = 0;
else if (baud <= 300) baud = 300;
if (baud <= 300)
baud = 300;
else if (baud <= 600) baud = 600;
else if (baud <= 1200) baud = 1200;
else if (baud <= 1800) baud = 1800;
......@@ -389,10 +394,10 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
else if (baud <= 491520) baud = 460800;
else if (baud <= 567138) baud = 500000;
else if (baud <= 670254) baud = 576000;
else if (baud <= 1053257) baud = 921600;
else if (baud <= 1474560) baud = 1228800;
else if (baud <= 2457600) baud = 1843200;
else baud = 3686400;
else if (baud < 1000000)
baud = 921600;
else if (baud > 2000000)
baud = 2000000;
return baud;
}
......@@ -409,13 +414,14 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
return result;
}
result = usb_serial_generic_open(tty, port);
if (result)
return result;
/* Configure the termios structure */
cp210x_get_termios(tty, port);
return 0;
/* The baud rate must be initialised on cp2104 */
if (tty)
cp210x_change_speed(tty, port, NULL);
return usb_serial_generic_open(tty, port);
}
static void cp210x_close(struct usb_serial_port *port)
......@@ -467,10 +473,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
dbg("%s - port %d", __func__, port->number);
cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2);
/* Convert to baudrate */
if (baud)
baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
dbg("%s - baud rate = %d", __func__, baud);
*baudp = baud;
......@@ -579,11 +582,64 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
*cflagp = cflag;
}
/*
* CP2101 supports the following baud rates:
*
* 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
* 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
*
* CP2102 and CP2103 support the following additional rates:
*
* 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
* 576000
*
* The device will map a requested rate to a supported one, but the result
* of requests for rates greater than 1053257 is undefined (see AN205).
*
* CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
* respectively, with an error less than 1%. The actual rates are determined
* by
*
* div = round(freq / (2 x prescale x request))
* actual = freq / (2 x prescale x div)
*
* For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
* or 1 otherwise.
* For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
* otherwise.
*/
static void cp210x_change_speed(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
u32 baud;
baud = tty->termios->c_ospeed;
/* This maps the requested rate to a rate valid on cp2102 or cp2103,
* or to an arbitrary rate in [1M,2M].
*
* NOTE: B0 is not implemented.
*/
baud = cp210x_quantise_baudrate(baud);
dbg("%s - setting baud rate to %u", __func__, baud);
if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud,
sizeof(baud))) {
dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
if (old_termios)
baud = old_termios->c_ospeed;
else
baud = 9600;
}
tty_encode_baud_rate(tty, baud, baud);
}
static void cp210x_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
unsigned int cflag, old_cflag;
unsigned int baud = 0, bits;
unsigned int bits;
unsigned int modem_ctl[4];
dbg("%s - port %d", __func__, port->number);
......@@ -593,20 +649,9 @@ static void cp210x_set_termios(struct tty_struct *tty,
cflag = tty->termios->c_cflag;
old_cflag = old_termios->c_cflag;
baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty));
/* If the baud rate is to be updated*/
if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
dbg("%s - Setting baud rate to %d baud", __func__,
baud);
if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
dbg("Baud rate requested not supported by device");
baud = tty_termios_baud_rate(old_termios);
}
}
/* Report back the resulting baud rate */
tty_encode_baud_rate(tty, baud, baud);
if (tty->termios->c_ospeed != old_termios->c_ospeed)
cp210x_change_speed(tty, port, old_termios);
/* If the number of data bits is to be updated */
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
......
......@@ -797,6 +797,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(HORNBY_VID, HORNBY_ELITE_PID) },
{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
......@@ -805,6 +806,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, TI_XDS100V2_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
{ USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
{ USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
......@@ -841,6 +844,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
.driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
......@@ -1333,8 +1337,7 @@ static int set_serial_info(struct tty_struct *tty,
goto check_and_exit;
}
if ((new_serial.baud_base != priv->baud_base) &&
(new_serial.baud_base < 9600)) {
if (new_serial.baud_base != priv->baud_base) {
mutex_unlock(&priv->cfg_lock);
return -EINVAL;
}
......@@ -1824,6 +1827,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ktermios dummy;
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
int result;
......@@ -1842,8 +1846,10 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
This is same behaviour as serial.c/rs_open() - Kuba */
/* ftdi_set_termios will send usb control messages */
if (tty)
ftdi_set_termios(tty, port, tty->termios);
if (tty) {
memset(&dummy, 0, sizeof(dummy));
ftdi_set_termios(tty, port, &dummy);
}
/* Start reading from the device */
result = usb_serial_generic_open(tty, port);
......
......@@ -39,6 +39,13 @@
/* www.candapter.com Ewert Energy Systems CANdapter device */
#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
/*
* Texas Instruments XDS100v2 JTAG / BeagleBone A3
* http://processors.wiki.ti.com/index.php/XDS100
* http://beagleboard.org/bone
*/
#define TI_XDS100V2_PID 0xa6d0
#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */
/* US Interface Navigator (http://www.usinterface.com/) */
......@@ -524,6 +531,12 @@
#define ADI_GNICE_PID 0xF000
#define ADI_GNICEPLUS_PID 0xF001
/*
* Hornby Elite
*/
#define HORNBY_VID 0x04D8
#define HORNBY_ELITE_PID 0x000A
/*
* RATOC REX-USB60F
*/
......@@ -1168,3 +1181,9 @@
*/
/* TagTracer MIFARE*/
#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0
/*
* Rainforest Automation
*/
/* ZigBee controller */
#define FTDI_RF_R106 0x8A28
......@@ -2657,15 +2657,7 @@ static int edge_startup(struct usb_serial *serial)
static void edge_disconnect(struct usb_serial *serial)
{
int i;
struct edgeport_port *edge_port;
dbg("%s", __func__);
for (i = 0; i < serial->num_ports; ++i) {
edge_port = usb_get_serial_port_data(serial->port[i]);
edge_remove_sysfs_attrs(edge_port->port);
}
}
static void edge_release(struct usb_serial *serial)
......@@ -2744,6 +2736,7 @@ static struct usb_serial_driver edgeport_1port_device = {
.disconnect = edge_disconnect,
.release = edge_release,
.port_probe = edge_create_sysfs_attrs,
.port_remove = edge_remove_sysfs_attrs,
.ioctl = edge_ioctl,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
......@@ -2775,6 +2768,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.disconnect = edge_disconnect,
.release = edge_release,
.port_probe = edge_create_sysfs_attrs,
.port_remove = edge_remove_sysfs_attrs,
.ioctl = edge_ioctl,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
......
......@@ -38,7 +38,7 @@
#include <linux/ioctl.h>
#include "kobil_sct.h"
static int debug;
static bool debug;
/* Version Information */
#define DRIVER_VERSION "21/05/2004"
......
......@@ -480,6 +480,10 @@ static void option_instat_callback(struct urb *urb);
#define ZD_VENDOR_ID 0x0685
#define ZD_PRODUCT_7000 0x7000
/* LG products */
#define LG_VENDOR_ID 0x1004
#define LG_PRODUCT_L02C 0x618f
/* some devices interfaces need special handling due to a number of reasons */
enum option_blacklist_reason {
OPTION_BLACKLIST_NONE = 0,
......@@ -1183,6 +1187,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },
{ USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) },
{ USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
......
......@@ -36,6 +36,7 @@
#define UTSTARCOM_PRODUCT_UM175_V1 0x3712
#define UTSTARCOM_PRODUCT_UM175_V2 0x3714
#define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715
#define PANTECH_PRODUCT_UML190_VZW 0x3716
#define PANTECH_PRODUCT_UML290_VZW 0x3718
/* CMOTECH devices */
......@@ -67,7 +68,11 @@ static struct usb_device_id id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) }, /* NMEA */
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) }, /* WMC */
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, /* DIAG */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
......
......@@ -789,7 +789,7 @@ static void rts51x_suspend_timer_fn(unsigned long data)
rts51x_set_stat(chip, RTS51X_STAT_SS);
/* ignore mass storage interface's children */
pm_suspend_ignore_children(&us->pusb_intf->dev, true);
usb_autopm_put_interface(us->pusb_intf);
usb_autopm_put_interface_async(us->pusb_intf);
US_DEBUGP("%s: RTS51X_STAT_SS 01,"
"intf->pm_usage_cnt:%d, power.usage:%d\n",
__func__,
......
......@@ -27,8 +27,6 @@
#define USB_SKEL_VENDOR_ID 0xfff0
#define USB_SKEL_PRODUCT_ID 0xfff0
static DEFINE_MUTEX(skel_mutex);
/* table of devices that work with this driver */
static const struct usb_device_id skel_table[] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
......@@ -101,25 +99,18 @@ static int skel_open(struct inode *inode, struct file *file)
goto exit;
}
mutex_lock(&skel_mutex);
dev = usb_get_intfdata(interface);
if (!dev) {
mutex_unlock(&skel_mutex);
retval = -ENODEV;
goto exit;
}
/* increment our usage count for the device */
kref_get(&dev->kref);
mutex_unlock(&skel_mutex);
/* lock the device to allow correctly handling errors
* in resumption */
mutex_lock(&dev->io_mutex);
if (!dev->interface) {
retval = -ENODEV;
goto out_err;
}
retval = usb_autopm_get_interface(interface);
if (retval)
......@@ -127,11 +118,7 @@ static int skel_open(struct inode *inode, struct file *file)
/* save our object in the file's private structure */
file->private_data = dev;
out_err:
mutex_unlock(&dev->io_mutex);
if (retval)
kref_put(&dev->kref, skel_delete);
exit:
return retval;
......@@ -611,6 +598,7 @@ static void skel_disconnect(struct usb_interface *interface)
int minor = interface->minor;
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &skel_class);
......@@ -622,12 +610,8 @@ static void skel_disconnect(struct usb_interface *interface)
usb_kill_anchored_urbs(&dev->submitted);
mutex_lock(&skel_mutex);
usb_set_intfdata(interface, NULL);
/* decrement our usage count */
kref_put(&dev->kref, skel_delete);
mutex_unlock(&skel_mutex);
dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
}
......
......@@ -6,7 +6,7 @@ config USB_WUSB
depends on EXPERIMENTAL
depends on USB
depends on PCI
select UWB
depends on UWB
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_CBC
......
/*
* Intel Langwell USB OTG transceiver driver
* Copyright (C) 2008 - 2010, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef __LANGWELL_OTG_H
#define __LANGWELL_OTG_H
#include <linux/usb/intel_mid_otg.h>
#define CI_USBCMD 0x30
# define USBCMD_RST BIT(1)
# define USBCMD_RS BIT(0)
#define CI_USBSTS 0x34
# define USBSTS_SLI BIT(8)
# define USBSTS_URI BIT(6)
# define USBSTS_PCI BIT(2)
#define CI_PORTSC1 0x74
# define PORTSC_PP BIT(12)
# define PORTSC_LS (BIT(11) | BIT(10))
# define PORTSC_SUSP BIT(7)
# define PORTSC_CCS BIT(0)
#define CI_HOSTPC1 0xb4
# define HOSTPC1_PHCD BIT(22)
#define CI_OTGSC 0xf4
# define OTGSC_DPIE BIT(30)
# define OTGSC_1MSE BIT(29)
# define OTGSC_BSEIE BIT(28)
# define OTGSC_BSVIE BIT(27)
# define OTGSC_ASVIE BIT(26)
# define OTGSC_AVVIE BIT(25)
# define OTGSC_IDIE BIT(24)
# define OTGSC_DPIS BIT(22)
# define OTGSC_1MSS BIT(21)
# define OTGSC_BSEIS BIT(20)
# define OTGSC_BSVIS BIT(19)
# define OTGSC_ASVIS BIT(18)
# define OTGSC_AVVIS BIT(17)
# define OTGSC_IDIS BIT(16)
# define OTGSC_DPS BIT(14)
# define OTGSC_1MST BIT(13)
# define OTGSC_BSE BIT(12)
# define OTGSC_BSV BIT(11)
# define OTGSC_ASV BIT(10)
# define OTGSC_AVV BIT(9)
# define OTGSC_ID BIT(8)
# define OTGSC_HABA BIT(7)
# define OTGSC_HADP BIT(6)
# define OTGSC_IDPU BIT(5)
# define OTGSC_DP BIT(4)
# define OTGSC_OT BIT(3)
# define OTGSC_HAAR BIT(2)
# define OTGSC_VC BIT(1)
# define OTGSC_VD BIT(0)
# define OTGSC_INTEN_MASK (0x7f << 24)
# define OTGSC_INT_MASK (0x5f << 24)
# define OTGSC_INTSTS_MASK (0x7f << 16)
#define CI_USBMODE 0xf8
# define USBMODE_CM (BIT(1) | BIT(0))
# define USBMODE_IDLE 0
# define USBMODE_DEVICE 0x2
# define USBMODE_HOST 0x3
#define USBCFG_ADDR 0xff10801c
#define USBCFG_LEN 4
# define USBCFG_VBUSVAL BIT(14)
# define USBCFG_AVALID BIT(13)
# define USBCFG_BVALID BIT(12)
# define USBCFG_SESEND BIT(11)
#define INTR_DUMMY_MASK (USBSTS_SLI | USBSTS_URI | USBSTS_PCI)
enum langwell_otg_timer_type {
TA_WAIT_VRISE_TMR,
TA_WAIT_BCON_TMR,
TA_AIDL_BDIS_TMR,
TB_ASE0_BRST_TMR,
TB_SE0_SRP_TMR,
TB_SRP_INIT_TMR,
TB_SRP_FAIL_TMR,
TB_BUS_SUSPEND_TMR
};
#define TA_WAIT_VRISE 100
#define TA_WAIT_BCON 30000
#define TA_AIDL_BDIS 15000
#define TB_ASE0_BRST 5000
#define TB_SE0_SRP 2
#define TB_SRP_INIT 100
#define TB_SRP_FAIL 5500
#define TB_BUS_SUSPEND 500
struct langwell_otg_timer {
unsigned long expires; /* Number of count increase to timeout */
unsigned long count; /* Tick counter */
void (*function)(unsigned long); /* Timeout function */
unsigned long data; /* Data passed to function */
struct list_head list;
};
struct langwell_otg {
struct intel_mid_otg_xceiv iotg;
struct device *dev;
void __iomem *usbcfg; /* SCCBUSB config Reg */
unsigned region;
unsigned cfg_region;
struct work_struct work;
struct workqueue_struct *qwork;
struct timer_list hsm_timer;
spinlock_t lock;
spinlock_t wq_lock;
struct notifier_block iotg_notifier;
};
static inline
struct langwell_otg *mid_xceiv_to_lnw(struct intel_mid_otg_xceiv *iotg)
{
return container_of(iotg, struct langwell_otg, iotg);
}
#endif /* __LANGWELL_OTG_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment