diff options
Diffstat (limited to 'drivers/misc/modem_if_na/modem_link_device_usb.c')
-rw-r--r-- | drivers/misc/modem_if_na/modem_link_device_usb.c | 1031 |
1 files changed, 0 insertions, 1031 deletions
diff --git a/drivers/misc/modem_if_na/modem_link_device_usb.c b/drivers/misc/modem_if_na/modem_link_device_usb.c deleted file mode 100644 index 6bdd7b5..0000000 --- a/drivers/misc/modem_if_na/modem_link_device_usb.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2010 Samsung Electronics. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#define DEBUG - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/sched.h> -#include <linux/irq.h> -#include <linux/poll.h> -#include <linux/gpio.h> -#include <linux/if_arp.h> -#include <linux/platform_device.h> -#include <linux/suspend.h> - -#include <linux/platform_data/modem_na.h> -#include "modem_prj.h" -#include "modem_link_device_usb.h" -#include "modem_link_pm_usb.h" - -#include <mach/regs-gpio.h> - -#define URB_COUNT 4 - -extern int factory_mode; - -static int enable_autosuspend; -static int wakelock_held; - -static int usb_tx_urb_with_skb(struct usb_link_device *usb_ld, - struct sk_buff *skb, struct if_usb_devdata *pipe_data); - -static void -usb_change_modem_state(struct usb_link_device *usb_ld, enum modem_state state); - -static int usb_attach_io_dev(struct link_device *ld, - struct io_device *iod) -{ - struct usb_link_device *usb_ld = to_usb_link_device(ld); - - iod->link = ld; - - /* list up io devices */ - list_add(&iod->list, &usb_ld->list_of_io_devices); - - return 0; -} - -static void -usb_free_urbs(struct usb_link_device *usb_ld, struct if_usb_devdata *pipe) -{ - struct usb_device *usbdev = usb_ld->usbdev; - struct urb *urb; - - while ((urb = usb_get_from_anchor(&pipe->urbs))) { - usb_poison_urb(urb); - usb_free_coherent(usbdev, pipe->rx_buf_size, - urb->transfer_buffer, urb->transfer_dma); - urb->transfer_buffer = NULL; - usb_put_urb(urb); - usb_free_urb(urb); - } -} - -static int usb_init_communication(struct link_device *ld, - struct io_device *iod) -{ - int err = 0; - switch (iod->format) { - case IPC_BOOT: - ld->com_state = COM_BOOT; - skb_queue_purge(&ld->sk_fmt_tx_q); - break; - - case IPC_RAMDUMP: - ld->com_state = COM_CRASH; - break; - - case IPC_FMT: - case IPC_RFS: - case IPC_RAW: - - default: - ld->com_state = COM_ONLINE; - break; - } - - mif_debug("com_state = %d\n", ld->com_state); - return err; -} - -static void usb_terminate_communication( - struct link_device *ld, struct io_device *iod) -{ - if (iod->format != IPC_BOOT && iod->format != IPC_RAMDUMP) - mif_debug("com_state = %d\n", ld->com_state); -} - -static int usb_rx_submit(struct if_usb_devdata *pipe, struct urb *urb, - gfp_t gfp_flags) -{ - int ret; - - usb_anchor_urb(urb, &pipe->reading); - ret = usb_submit_urb(urb, gfp_flags); - if (ret) { - usb_unanchor_urb(urb); - usb_anchor_urb(urb, &pipe->urbs); - mif_err("submit urb fail with ret (%d)\n", ret); - } - - usb_mark_last_busy(urb->dev); - return ret; -} - -static void usb_rx_complete(struct urb *urb) -{ - struct if_usb_devdata *pipe_data = urb->context; - struct usb_link_device *usb_ld = usb_get_intfdata(pipe_data->data_intf); - struct io_device *iod; - int iod_format = IPC_FMT; - int ret; - - usb_mark_last_busy(urb->dev); - - switch (urb->status) { - case 0: - case -ENOENT: - if (!urb->actual_length) - goto re_submit; - /* call iod recv */ - /* how we can distinguish boot ch with fmt ch ?? */ - switch (pipe_data->format) { - case IF_USB_FMT_EP: - iod_format = IPC_FMT; - /* - print_hex_dump(KERN_INFO, "[FMT-RX] ", - DUMP_PREFIX_OFFSET, 16, 1, - urb->transfer_buffer, - min(urb->actual_length, (u32)64), true); - */ - break; - case IF_USB_RAW_EP: - iod_format = IPC_MULTI_RAW; - break; - case IF_USB_RFS_EP: - iod_format = IPC_RFS; - break; - default: - break; - } - - list_for_each_entry(iod, &usb_ld->list_of_io_devices, list) { - /* during boot stage fmt end point */ - /* shared with boot io device */ - /* when we use fmt device only, at boot and ipc exchange - it can be reduced to 1 device */ - if (iod_format == IPC_FMT && - usb_ld->ld.com_state == COM_BOOT) - iod_format = IPC_BOOT; - if (iod_format == IPC_FMT && - usb_ld->ld.com_state == COM_CRASH) - iod_format = IPC_RAMDUMP; - - if (iod->format == iod_format) { - ret = iod->recv(iod, - (char *)urb->transfer_buffer, - urb->actual_length); - if (ret < 0) - mif_err("io device recv error :%d\n", - ret); - break; - } - } -re_submit: - if (urb->status || atomic_read(&usb_ld->suspend_count)) - break; - - usb_mark_last_busy(urb->dev); - usb_rx_submit(pipe_data, urb, GFP_ATOMIC); - return; - case -ESHUTDOWN: - case -EPROTO: - break; - case -EOVERFLOW: - mif_err("RX overflow\n"); - break; - default: - mif_err("RX complete Status (%d)\n", urb->status); - break; - } - - usb_anchor_urb(urb, &pipe_data->urbs); -} - -static int usb_send(struct link_device *ld, struct io_device *iod, - struct sk_buff *skb) -{ - struct sk_buff_head *txq; - - if (iod->format == IPC_RAW) - txq = &ld->sk_raw_tx_q; - else - txq = &ld->sk_fmt_tx_q; - - /* save io device into cb area */ - *((struct io_device **)skb->cb) = iod; - /* en queue skb data */ - skb_queue_tail(txq, skb); - - queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work, 0); - - return skb->len; -} - -static void usb_tx_complete(struct urb *urb) -{ - int ret = 0; - struct sk_buff *skb = urb->context; - - switch (urb->status) { - case 0: - break; - default: - mif_err("TX error (%d)\n", urb->status); - } - - usb_mark_last_busy(urb->dev); - ret = pm_runtime_put_autosuspend(&urb->dev->dev); - if (ret < 0) - mif_debug("pm_runtime_put_autosuspend failed : ret(%d)\n", ret); - usb_free_urb(urb); - dev_kfree_skb_any(skb); -} - -static void if_usb_force_disconnect(struct work_struct *work) -{ - struct usb_link_device *usb_ld = - container_of(work, struct usb_link_device, disconnect_work); - struct usb_device *udev = usb_ld->usbdev; - - if (!udev || !(&udev->dev)) - return; - - pm_runtime_get_sync(&udev->dev); - if (udev->state != USB_STATE_NOTATTACHED) { - usb_force_disconnect(udev); - mif_info("force disconnect by modem not responding!!\n"); - } - pm_runtime_put_autosuspend(&udev->dev); -} - -static void -usb_change_modem_state(struct usb_link_device *usb_ld, enum modem_state state) -{ - struct io_device *iod; - - list_for_each_entry(iod, &usb_ld->list_of_io_devices, list) { - if (iod->format == IPC_FMT) { - iod->modem_state_changed(iod, state); - return; - } - } -} - -static int usb_tx_urb_with_skb(struct usb_link_device *usb_ld, - struct sk_buff *skb, struct if_usb_devdata *pipe_data) -{ - int ret, cnt = 0; - struct urb *urb; - struct usb_device *usbdev = usb_ld->usbdev; - unsigned long flags; - - if (!usbdev || (usbdev->state == USB_STATE_NOTATTACHED) || - usb_ld->host_wake_timeout_flag) - return -ENODEV; - - pm_runtime_get_noresume(&usbdev->dev); - - if (usbdev->dev.power.runtime_status == RPM_SUSPENDED || - usbdev->dev.power.runtime_status == RPM_SUSPENDING) { - usb_ld->resume_status = AP_INITIATED_RESUME; - SET_SLAVE_WAKEUP(usb_ld->pdata, 1); - - while (!wait_event_interruptible_timeout(usb_ld->l2_wait, - usbdev->dev.power.runtime_status == RPM_ACTIVE - || pipe_data->disconnected, - HOST_WAKEUP_TIMEOUT_JIFFIES)) { - - if (cnt == MAX_RETRY) { - mif_err("host wakeup timeout !!\n"); - SET_SLAVE_WAKEUP(usb_ld->pdata, 0); - pm_runtime_put_autosuspend(&usbdev->dev); - schedule_work(&usb_ld->disconnect_work); - usb_ld->host_wake_timeout_flag = 1; - return -1; - } - mif_err("host wakeup timeout ! retry..\n"); - SET_SLAVE_WAKEUP(usb_ld->pdata, 0); - udelay(100); - SET_SLAVE_WAKEUP(usb_ld->pdata, 1); - cnt++; - } - - if (pipe_data->disconnected) { - SET_SLAVE_WAKEUP(usb_ld->pdata, 0); - pm_runtime_put_autosuspend(&usbdev->dev); - return -ENODEV; - } - - mif_debug("wait_q done (runtime_status=%d)\n", - usbdev->dev.power.runtime_status); - } - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - mif_err("alloc urb error\n"); - if (pm_runtime_put_autosuspend(&usbdev->dev) < 0) - mif_debug("pm_runtime_put_autosuspend fail\n"); - return -ENOMEM; - } - - urb->transfer_flags = URB_ZERO_PACKET; - usb_fill_bulk_urb(urb, usbdev, pipe_data->tx_pipe, skb->data, - skb->len, usb_tx_complete, (void *)skb); - - spin_lock_irqsave(&usb_ld->lock, flags); - if (atomic_read(&usb_ld->suspend_count)) { - /* transmission will be done in resume */ - usb_anchor_urb(urb, &usb_ld->deferred); - usb_put_urb(urb); - mif_debug("anchor urb (0x%p)\n", urb); - spin_unlock_irqrestore(&usb_ld->lock, flags); - return 0; - } - spin_unlock_irqrestore(&usb_ld->lock, flags); - - ret = usb_submit_urb(urb, GFP_KERNEL); - if (ret < 0) { - mif_err("usb_submit_urb with ret(%d)\n", ret); - if (pm_runtime_put_autosuspend(&usbdev->dev) < 0) - mif_debug("pm_runtime_put_autosuspend fail\n"); - } - return ret; -} - -static void usb_tx_work(struct work_struct *work) -{ - int ret = 0; - struct link_device *ld = - container_of(work, struct link_device, tx_delayed_work.work); - struct usb_link_device *usb_ld = to_usb_link_device(ld); - struct io_device *iod; - struct sk_buff *skb; - struct if_usb_devdata *pipe_data; - struct link_pm_data *pm_data = usb_ld->link_pm_data; - - /*TODO: check the PHONE ACTIVE STATES */ - /* because tx data wait until hub on with wait_for_complettion, it - should queue to single_threaded work queue */ - if (!link_pm_set_active(usb_ld)) - return; - - while (ld->sk_fmt_tx_q.qlen || ld->sk_raw_tx_q.qlen) { - /* send skb from fmt_txq and raw_txq, - * one by one for fair flow control */ - skb = skb_dequeue(&ld->sk_fmt_tx_q); - if (skb) { - iod = *((struct io_device **)skb->cb); - switch (iod->format) { - case IPC_FMT: - /* - print_hex_dump(KERN_INFO, "[FMT-TX] ", - DUMP_PREFIX_OFFSET, 16, 1, - skb->data, - min(skb->len, (u32)64), true); - */ - case IPC_BOOT: - case IPC_RAMDUMP: - /* boot device uses same intf with fmt*/ - pipe_data = &usb_ld->devdata[IF_USB_FMT_EP]; - break; - case IPC_RFS: - pipe_data = &usb_ld->devdata[IF_USB_RFS_EP]; - break; - default: - /* wrong packet for fmt tx q , drop it */ - dev_kfree_skb_any(skb); - continue; - } - - ret = usb_tx_urb_with_skb(usb_ld, skb, pipe_data); - if (ret < 0) { - mif_err("usb_tx_urb_with_skb, ret(%d)\n", - ret); - skb_queue_head(&ld->sk_fmt_tx_q, skb); - - if (edc_inc(&usb_ld->urb_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) { - mif_err("maximum error in URB exceeded\n"); - usb_change_modem_state(usb_ld, - STATE_CRASH_EXIT); - } - return; - } - } - - skb = skb_dequeue(&ld->sk_raw_tx_q); - if (skb) { - pipe_data = &usb_ld->devdata[IF_USB_RAW_EP]; - ret = usb_tx_urb_with_skb(usb_ld, skb, pipe_data); - if (ret < 0) { - mif_err("usb_tx_urb_with_skb " - "for raw, ret(%d)\n", - ret); - skb_queue_head(&ld->sk_raw_tx_q, skb); - - if (edc_inc(&usb_ld->urb_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) { - mif_err("maximum error in URB exceeded\n"); - usb_change_modem_state(usb_ld, - STATE_CRASH_EXIT); - } - return; - } - } - } -} - -static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usb_link_device *usb_ld = usb_get_intfdata(intf); - int i; - - if (atomic_inc_return(&usb_ld->suspend_count) == IF_USB_DEVNUM_MAX) { - mif_debug("L2\n"); - - for (i = 0; i < IF_USB_DEVNUM_MAX; i++) - usb_kill_anchored_urbs(&usb_ld->devdata[i].reading); - - /* - if (usb_ld->link_pm_data->cpufreq_unlock) - usb_ld->link_pm_data->cpufreq_unlock(); - */ - if (wakelock_held) { - wakelock_held = 0; - wake_unlock(&usb_ld->susplock); - } - } - - return 0; -} - -static void runtime_pm_work(struct work_struct *work) -{ - struct usb_link_device *usb_ld = container_of(work, - struct usb_link_device, runtime_pm_work.work); - int ret; - - ret = pm_request_autosuspend(&usb_ld->usbdev->dev); - - if (ret == -EAGAIN || ret == 1) - queue_delayed_work(system_nrt_wq, &usb_ld->runtime_pm_work, - msecs_to_jiffies(50)); -} - -static void post_resume_work(struct work_struct *work) -{ - struct usb_link_device *usb_ld = container_of(work, - struct usb_link_device, post_resume_work.work); - - /* lock cpu frequency when L2->L0 */ - /* - if (usb_ld->link_pm_data->cpufreq_lock) - usb_ld->link_pm_data->cpufreq_lock(); - */ -} - -static void wait_enumeration_work(struct work_struct *work) -{ - struct usb_link_device *usb_ld = container_of(work, - struct usb_link_device, wait_enumeration.work); - - /* Work around code for factory device test & verification. - * To measure device sleep current speedly, do not call silent reset in - * factory mode. CMC22x disconect usb forcely and go sleep - * without normal L3 process if in factory mode. Also AP do. */ - if (factory_mode) - return; - - if (usb_ld->if_usb_connected == 0) { - mif_err("USB disconnected and not enumerated for long time\n"); - usb_change_modem_state(usb_ld, STATE_CRASH_EXIT); - } -} - -static int if_usb_resume(struct usb_interface *intf) -{ - int i, ret; - struct sk_buff *skb; - struct usb_link_device *usb_ld = usb_get_intfdata(intf); - struct if_usb_devdata *pipe; - struct urb *urb; - - spin_lock_irq(&usb_ld->lock); - if (!atomic_dec_return(&usb_ld->suspend_count)) { - spin_unlock_irq(&usb_ld->lock); - - mif_debug("\n"); - wake_lock(&usb_ld->susplock); - wakelock_held = 1; - - /* HACK: Runtime pm does not allow requesting autosuspend from - * resume callback, delayed it after resume */ - queue_delayed_work(system_nrt_wq, &usb_ld->runtime_pm_work, - msecs_to_jiffies(50)); - - for (i = 0; i < IF_USB_DEVNUM_MAX; i++) { - pipe = &usb_ld->devdata[i]; - while ((urb = usb_get_from_anchor(&pipe->urbs))) { - ret = usb_rx_submit(pipe, urb, GFP_KERNEL); - if (ret < 0) { - usb_put_urb(urb); - mif_err( - "usb_rx_submit error with (%d)\n", - ret); - return ret; - } - usb_put_urb(urb); - } - } - - while ((urb = usb_get_from_anchor(&usb_ld->deferred))) { - mif_debug("got urb (0x%p) from anchor & resubmit\n", - urb); - ret = usb_submit_urb(urb, GFP_KERNEL); - if (ret < 0) { - mif_err("resubmit failed\n"); - skb = urb->context; - dev_kfree_skb_any(skb); - usb_free_urb(urb); - if (pm_runtime_put_autosuspend( - &usb_ld->usbdev->dev) < 0) - mif_debug( - "pm_runtime_put_autosuspend fail\n"); - } - } - SET_SLAVE_WAKEUP(usb_ld->pdata, 1); - udelay(100); - SET_SLAVE_WAKEUP(usb_ld->pdata, 0); - - if (!link_pm_is_connected(usb_ld)) - enable_autosuspend = 1; - - /* if_usb_resume() is atomic. post_resume_work is - * a kind of bottom halves - */ - /* - queue_delayed_work(system_nrt_wq, &usb_ld->post_resume_work, 0); - */ - - return 0; - } - - spin_unlock_irq(&usb_ld->lock); - return 0; -} - -static int if_usb_reset_resume(struct usb_interface *intf) -{ - int ret; - - mif_debug("\n"); - ret = if_usb_resume(intf); - return ret; -} - -static struct usb_device_id if_usb_ids[] = { - { USB_DEVICE(0x04e8, 0x6999), /* CMC221 LTE Modem */ - /*.driver_info = 0,*/ - }, - { } /* terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, if_usb_ids); - -static struct usb_driver if_usb_driver; -static void if_usb_disconnect(struct usb_interface *intf) -{ - struct usb_link_device *usb_ld = usb_get_intfdata(intf); - struct usb_device *usbdev = usb_ld->usbdev; - int dev_id = intf->altsetting->desc.bInterfaceNumber; - struct if_usb_devdata *pipe_data = &usb_ld->devdata[dev_id]; - - usb_set_intfdata(intf, NULL); - - pipe_data->disconnected = 1; - smp_wmb(); - - wake_up(&usb_ld->l2_wait); - if (wakelock_held) { - wakelock_held = 0; - wake_unlock(&usb_ld->susplock); - } - /* - if (usb_ld->if_usb_connected) { - disable_irq_wake(usb_ld->pdata->irq_host_wakeup); - free_irq(usb_ld->pdata->irq_host_wakeup, usb_ld); - } - */ - - usb_ld->if_usb_connected = 0; - usb_ld->flow_suspend = 1; - - dev_dbg(&usbdev->dev, "%s\n", __func__); - usb_ld->dev_count--; - usb_driver_release_interface(&if_usb_driver, pipe_data->data_intf); - - usb_kill_anchored_urbs(&pipe_data->reading); - usb_free_urbs(usb_ld, pipe_data); - - if (usb_ld->dev_count == 0) { - cancel_delayed_work_sync(&usb_ld->runtime_pm_work); - /* - cancel_delayed_work_sync(&usb_ld->post_resume_work); - */ - cancel_delayed_work_sync(&usb_ld->ld.tx_delayed_work); - cancel_work_sync(&usb_ld->disconnect_work); - usb_put_dev(usbdev); - usb_ld->usbdev = NULL; - - wake_lock(&usb_ld->link_pm_data->boot_wake); - - schedule_delayed_work(&usb_ld->wait_enumeration, - WAIT_ENUMURATION_TIMEOUT_JIFFIES); - } -} - -static int __devinit if_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_host_interface *data_desc; - struct usb_link_device *usb_ld = - (struct usb_link_device *)id->driver_info; - struct link_device *ld = &usb_ld->ld; - struct usb_interface *data_intf; - struct usb_device *usbdev = interface_to_usbdev(intf); - struct device *dev; - struct if_usb_devdata *pipe; - struct urb *urb; - int i; - int j; - int dev_id; - int err; - - /* To detect usb device order probed */ - dev_id = intf->cur_altsetting->desc.bInterfaceNumber; - - if (dev_id >= IF_USB_DEVNUM_MAX) { - dev_err(&intf->dev, "Device id %d cannot support\n", - dev_id); - return -EINVAL; - } - - if (!usb_ld) { - dev_err(&intf->dev, - "if_usb device doesn't be allocated\n"); - err = ENOMEM; - goto out; - } - - mif_info("probe dev_id=%d usb_device_id(0x%p), usb_ld (0x%p)\n", - dev_id, id, usb_ld); - - usb_ld->usbdev = usbdev; - - usb_get_dev(usbdev); - - for (i = 0; i < IF_USB_DEVNUM_MAX; i++) { - data_intf = usb_ifnum_to_if(usbdev, i); - - /* remap endpoint of RAW to no.1 for LTE modem */ - if (i == 0) - pipe = &usb_ld->devdata[1]; - else if (i == 1) - pipe = &usb_ld->devdata[0]; - else - pipe = &usb_ld->devdata[i]; - - pipe->disconnected = 0; - pipe->data_intf = data_intf; - data_desc = data_intf->cur_altsetting; - - /* Endpoints */ - if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) { - pipe->rx_pipe = usb_rcvbulkpipe(usbdev, - data_desc->endpoint[0].desc.bEndpointAddress); - pipe->tx_pipe = usb_sndbulkpipe(usbdev, - data_desc->endpoint[1].desc.bEndpointAddress); - pipe->rx_buf_size = 1024*4; - } else { - pipe->rx_pipe = usb_rcvbulkpipe(usbdev, - data_desc->endpoint[1].desc.bEndpointAddress); - pipe->tx_pipe = usb_sndbulkpipe(usbdev, - data_desc->endpoint[0].desc.bEndpointAddress); - pipe->rx_buf_size = 1024*4; - } - - if (i == 0) { - dev_info(&usbdev->dev, "USB IF USB device found\n"); - } else { - err = usb_driver_claim_interface(&if_usb_driver, - data_intf, usb_ld); - if (err < 0) { - mif_err("failed to cliam usb interface\n"); - goto out; - } - } - - usb_set_intfdata(data_intf, usb_ld); - usb_ld->dev_count++; - pm_suspend_ignore_children(&data_intf->dev, true); - - for (j = 0; j < URB_COUNT; j++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - mif_err("alloc urb fail\n"); - err = -ENOMEM; - goto out2; - } - - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - urb->transfer_buffer = usb_alloc_coherent(usbdev, - pipe->rx_buf_size, GFP_KERNEL, - &urb->transfer_dma); - if (!urb->transfer_buffer) { - mif_err( - "Failed to allocate transfer buffer\n"); - usb_free_urb(urb); - err = -ENOMEM; - goto out2; - } - - usb_fill_bulk_urb(urb, usbdev, pipe->rx_pipe, - urb->transfer_buffer, pipe->rx_buf_size, - usb_rx_complete, pipe); - usb_anchor_urb(urb, &pipe->urbs); - } - } - - /* temporary call reset_resume */ - atomic_set(&usb_ld->suspend_count, 1); - if_usb_reset_resume(data_intf); - atomic_set(&usb_ld->suspend_count, 0); - - SET_HOST_ACTIVE(usb_ld->pdata, 1); - usb_ld->host_wake_timeout_flag = 0; - - if (gpio_get_value(usb_ld->pdata->gpio_phone_active)) { - struct link_pm_data *pm_data = usb_ld->link_pm_data; - int delay = AUTOSUSPEND_DELAY_MS; - pm_runtime_set_autosuspend_delay(&usbdev->dev, delay); - dev = &usb_ld->usbdev->dev; - if (dev->parent) { - dev_dbg(&usbdev->dev, "if_usb Runtime PM Start!!\n"); - usb_enable_autosuspend(usb_ld->usbdev); - pm_runtime_allow(dev); - - if (pm_data->block_autosuspend) - pm_runtime_forbid(dev); - } - - enable_irq_wake(usb_ld->pdata->irq_host_wakeup); - - usb_ld->flow_suspend = 0; - /* Queue work if skbs were pending before a disconnect/probe */ - if (ld->sk_fmt_tx_q.qlen || ld->sk_raw_tx_q.qlen) - queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work, 0); - - wake_unlock(&usb_ld->link_pm_data->boot_wake); - - usb_ld->if_usb_connected = 1; - usb_change_modem_state(usb_ld, STATE_ONLINE); - } else { - usb_change_modem_state(usb_ld, STATE_LOADER_DONE); - } - - edc_init(&usb_ld->urb_edc); - - return 0; - -out2: - usb_ld->dev_count--; - for (i = 0; i < IF_USB_DEVNUM_MAX; i++) - usb_free_urbs(usb_ld, &usb_ld->devdata[i]); -out: - usb_set_intfdata(intf, NULL); - return err; -} - -irqreturn_t usb_resume_irq(int irq, void *data) -{ - int ret; - struct usb_link_device *usb_ld = data; - int hwup; - static int wake_status = -1; - struct device *dev; - - hwup = gpio_get_value(usb_ld->pdata->gpio_host_wakeup); - if (hwup == wake_status) { - mif_err("Received spurious wake irq: %d", hwup); - return IRQ_HANDLED; - } - wake_status = hwup; - - irq_set_irq_type(irq, hwup ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); - /* - * exynos BSP has problem when using level interrupt. - * If we change irq type from interrupt handler, - * we can get level interrupt twice. - * this is temporary solution until SYS.LSI resolve this problem. - */ - __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq))); - wake_lock_timeout(&usb_ld->gpiolock, 100); - - mif_err("< H-WUP %d\n", hwup); - - if (!link_pm_is_connected(usb_ld) && - !(!hwup && enable_autosuspend)) { - return IRQ_HANDLED; - } else { - enable_autosuspend = 0; - } - - if (hwup) { - dev = &usb_ld->usbdev->dev; - mif_info("runtime status=%d\n", - dev->power.runtime_status); - - /* if usb3503 was on, usb_if was resumed by probe */ - /* - if (has_hub(usb_ld) && - (dev->power.runtime_status == RPM_ACTIVE || - dev->power.runtime_status == RPM_RESUMING)) - return IRQ_HANDLED; - */ - - device_lock(dev); - if (dev->power.is_prepared || dev->power.is_suspended) { - pm_runtime_get_noresume(dev); - ret = 0; - } else { - ret = pm_runtime_get_sync(dev); - } - device_unlock(dev); - if (ret < 0) { - mif_err("pm_runtime_get fail (%d)\n", ret); - return IRQ_HANDLED; - } - } else { - if (usb_ld->resume_status == AP_INITIATED_RESUME) - wake_up(&usb_ld->l2_wait); - usb_ld->resume_status = CP_INITIATED_RESUME; - pm_runtime_mark_last_busy(&usb_ld->usbdev->dev); - pm_runtime_put_autosuspend(&usb_ld->usbdev->dev); - } - - return IRQ_HANDLED; -} - -static int if_usb_init(struct usb_link_device *usb_ld) -{ - int ret; - int i; - struct if_usb_devdata *pipe; - - /* give it to probe, or global variable needed */ - if_usb_ids[0].driver_info = (unsigned long)usb_ld; - - for (i = 0; i < IF_USB_DEVNUM_MAX; i++) { - pipe = &usb_ld->devdata[i]; - pipe->format = i; - pipe->disconnected = 1; - init_usb_anchor(&pipe->urbs); - init_usb_anchor(&pipe->reading); - } - - init_waitqueue_head(&usb_ld->l2_wait); - init_usb_anchor(&usb_ld->deferred); - - ret = usb_register(&if_usb_driver); - if (ret) { - mif_err("usb_register_driver() fail : %d\n", ret); - return ret; - } - - return 0; -} - -struct link_device *usb_create_link_device(void *data) -{ - int ret; - struct modem_data *pdata; - struct platform_device *pdev = (struct platform_device *)data; - struct usb_link_device *usb_ld = NULL; - struct link_device *ld = NULL; - - pdata = pdev->dev.platform_data; - - usb_ld = kzalloc(sizeof(struct usb_link_device), GFP_KERNEL); - if (!usb_ld) - goto err; - - INIT_LIST_HEAD(&usb_ld->list_of_io_devices); - skb_queue_head_init(&usb_ld->ld.sk_fmt_tx_q); - skb_queue_head_init(&usb_ld->ld.sk_raw_tx_q); - spin_lock_init(&usb_ld->lock); - - ld = &usb_ld->ld; - usb_ld->pdata = pdata; - - ld->name = "usb"; - ld->attach = usb_attach_io_dev; - ld->init_comm = usb_init_communication; - ld->terminate_comm = usb_terminate_communication; - ld->send = usb_send; - ld->com_state = COM_NONE; - - /*ld->tx_wq = create_singlethread_workqueue("usb_tx_wq");*/ - ld->tx_wq = alloc_workqueue("usb_tx_wq", - WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1); - - if (!ld->tx_wq) { - mif_err("fail to create work Q.\n"); - goto err; - } - - usb_ld->pdata->irq_host_wakeup = gpio_to_irq(platform_get_irq(pdev, 1)); - wake_lock_init(&usb_ld->gpiolock, WAKE_LOCK_SUSPEND, - "modem_usb_gpio_wake"); - wake_lock_init(&usb_ld->susplock, WAKE_LOCK_SUSPEND, - "modem_usb_suspend_block"); - - INIT_DELAYED_WORK(&ld->tx_delayed_work, usb_tx_work); - INIT_DELAYED_WORK(&usb_ld->runtime_pm_work, runtime_pm_work); - /* - INIT_DELAYED_WORK(&usb_ld->post_resume_work, post_resume_work); - */ - INIT_DELAYED_WORK(&usb_ld->wait_enumeration, wait_enumeration_work); - INIT_WORK(&usb_ld->disconnect_work, if_usb_force_disconnect); - - /* create link pm device */ - ret = link_pm_init(usb_ld, data); - if (ret) - goto err; - - ret = if_usb_init(usb_ld); - if (ret) - goto err; - - return ld; -err: - if (ld && ld->tx_wq) - destroy_workqueue(ld->tx_wq); - - kfree(usb_ld); - - return NULL; -} - -static struct usb_driver if_usb_driver = { - .name = "if_usb_driver", - .probe = if_usb_probe, - .disconnect = if_usb_disconnect, - .id_table = if_usb_ids, - .suspend = if_usb_suspend, - .resume = if_usb_resume, - .reset_resume = if_usb_reset_resume, - .supports_autosuspend = 1, -}; - -static void __exit if_usb_exit(void) -{ - usb_deregister(&if_usb_driver); -} - - -/* lte specific functions */ - -static int lte_wake_resume(struct device *pdev) -{ - struct modem_data *pdata = pdev->platform_data; - int val; - - val = gpio_get_value(pdata->gpio_host_wakeup); - if (!val) { - mif_debug("> S-WUP 1\n"); - gpio_set_value(pdata->gpio_slave_wakeup, 1); - } - - return 0; -} - -static const struct dev_pm_ops lte_wake_pm_ops = { - .resume = lte_wake_resume, -}; - -static struct platform_driver lte_wake_driver = { - .driver = { - .name = "modem_lte_wake", - .pm = <e_wake_pm_ops, - }, -}; - -static int __init lte_wake_init(void) -{ - return platform_driver_register(<e_wake_driver); -} -module_init(lte_wake_init); |