static int __init usb_notify_init(void) { pr_info("Starting USB Notify Subscriber\n"); usb_register_notify(&usb_notify_dev_nb); usb_register_notify(&usb_notify_bus_nb); return 0; }
static int __init my_init (void) { usb_register_notify (&my_nh_block); printk (KERN_INFO "USB Notifier module successfully loaded\n"); return 0; }
static int msm_otg_set_host(struct otg_transceiver *xceiv, struct usb_bus *host) { struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg); if (!dev || (dev != the_msm_otg)) return -ENODEV; /* Id pin is not routed to PMIC. Host mode can not be * supported with pmic notification support. */ if (!dev->start_host || dev->pmic_notif_supp) return -ENODEV; if (!host) { msm_otg_start_host(xceiv, REQUEST_STOP); usb_unregister_notify(&dev->usbdev_nb); dev->otg.host = 0; dev->start_host = 0; disable_idgnd(dev); return 0; } dev->usbdev_nb.notifier_call = usbdev_notify; usb_register_notify(&dev->usbdev_nb); dev->otg.host = host; enable_idgnd(dev); pr_info("host driver registered w/ tranceiver\n"); #ifdef CONFIG_USB_OTG host->otg_port = 1; #else wake_lock(&dev->wlock); queue_work(dev->wq, &dev->sm_work); #endif return 0; }
int hif_register_driver(void) { is_usb_driver_register = 1; init_waitqueue_head(&hif_usb_unload_event_wq); atomic_set(&hif_usb_unload_state, HIF_USB_UNLOAD_STATE_NULL); usb_register_notify(&hif_usb_dev_nb); return usb_register(&hif_usb_drv_id); }
static void usbdev_trig_activate(struct led_classdev *led_cdev) { struct usbdev_trig_data *td; int rc; td = kzalloc(sizeof(struct usbdev_trig_data), GFP_KERNEL); if (!td) return; rwlock_init(&td->lock); td->notifier.notifier_call = usbdev_trig_notify; td->notifier.priority = 10; setup_timer(&td->timer, usbdev_trig_timer, (unsigned long) td); td->led_cdev = led_cdev; td->interval = msecs_to_jiffies(50); led_cdev->trigger_data = td; rc = device_create_file(led_cdev->dev, &dev_attr_device_name); if (rc) goto err_out; rc = device_create_file(led_cdev->dev, &dev_attr_activity_interval); if (rc) goto err_out_device_name; usb_register_notify(&td->notifier); return; err_out_device_name: device_remove_file(led_cdev->dev, &dev_attr_device_name); err_out: led_cdev->trigger_data = NULL; kfree(td); }
static int __init wusbcore_init(void) { int result; result = wusb_crypto_init(); if (result < 0) goto error_crypto_init; /* WQ is singlethread because we need to serialize notifications */ wusbd = create_singlethread_workqueue("wusbd"); if (wusbd == NULL) { result = -ENOMEM; printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n"); goto error_wusbd_create; } usb_register_notify(&wusb_usb_notifier); bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS); set_bit(0, wusb_cluster_id_table); /* reserve Cluster ID 0xff */ return 0; error_wusbd_create: wusb_crypto_exit(); error_crypto_init: return result; }
static int ehci_hsic_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct hc_driver *driver; struct usb_hcd *hcd; struct ehci_hcd *ehci; int irq, retval; pr_debug("initializing Intel EHCI HSIC Host Controller\n"); if (usb_disabled()) return -ENODEV; if (!id) return -EINVAL; pci_dev = pdev; if (pci_enable_device(pdev) < 0) return -ENODEV; pdev->current_state = PCI_D0; wake_lock_init(&hsic.resume_wake_lock, WAKE_LOCK_SUSPEND, "hsic_aux2_wlock"); wake_lock_init(&hsic.s3_wake_lock, WAKE_LOCK_SUSPEND, "hsic_s3_wlock"); hsic.hsic_pm_nb.notifier_call = hsic_pm_notify; usb_register_notify(&hsic.hsic_pm_nb); hsic.hsic_s3_entry_nb.notifier_call = hsic_s3_entry_notify; register_pm_notifier(&hsic.hsic_s3_entry_nb); /* we need not call pci_enable_dev since otg transceiver already take * the control of this device and this probe actaully gets called by * otg transceiver driver with HNP protocol. */ irq = pdev->irq; if (!pdev->irq) { dev_dbg(&pdev->dev, "No IRQ.\n"); retval = -ENODEV; goto disable_pci; } driver = (struct hc_driver *)id->driver_data; if (!driver) return -EINVAL; /* AUX GPIO init */ retval = hsic_aux_gpio_init(); if (retval < 0) { dev_err(&pdev->dev, "AUX GPIO init fail\n"); retval = -ENODEV; goto disable_pci; } /* AUX GPIO init */ retval = hsic_wakeup_gpio_init(); if (retval < 0) { dev_err(&pdev->dev, "Wakeup GPIO init fail\n"); retval = -ENODEV; goto disable_pci; } hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { retval = -ENOMEM; goto disable_pci; } ehci = hcd_to_ehci(hcd); hcd->rsrc_start = pci_resource_start(pdev, 0); hcd->rsrc_len = pci_resource_len(pdev, 0); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { dev_dbg(&pdev->dev, "controller already in use\n"); retval = -EBUSY; goto clear_companion; } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { dev_dbg(&pdev->dev, "error mapping memory\n"); retval = -EFAULT; goto release_mem_region; } pci_set_master(pdev); if (hsic.hsic_enable_created == 0) { retval = create_device_files(); if (retval < 0) { dev_dbg(&pdev->dev, "error create device files\n"); goto release_mem_region; } hsic.hsic_enable_created = 1; } if (hsic.hsic_mutex_init == 0) { mutex_init(&hsic.hsic_mutex); mutex_init(&hsic.wlock_mutex); hsic.hsic_mutex_init = 1; } if (hsic.aux_wq_init == 0) { init_waitqueue_head(&hsic.aux_wq); hsic.aux_wq_init = 1; } hsic.work_queue = create_singlethread_workqueue("hsic"); INIT_DELAYED_WORK(&hsic.wakeup_work, wakeup_work); INIT_DELAYED_WORK(&(hsic.hsic_aux), hsic_aux_work); hcd->hsic_notify = hsic_notify; retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED | IRQF_NO_SUSPEND); if (retval != 0) goto unmap_registers; dev_set_drvdata(&pdev->dev, hcd); /* Clear phy low power mode, enable phy clock */ ehci_hsic_phy_power(ehci, 0); if (pci_dev_run_wake(pdev)) pm_runtime_put_noidle(&pdev->dev); if (!enabling_disabling) { /* Check here to avoid to call pm_runtime_put_noidle() twice */ if (!pci_dev_run_wake(pdev)) pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); } hsic.hsic_stopped = 0; hsic_enable = 1; hsic.s3_rt_state = RESUMED; s3_wake_lock(); hsic_debugfs_init(hcd); return retval; unmap_registers: destroy_workqueue(hsic.work_queue); if (driver->flags & HCD_MEMORY) { iounmap(hcd->regs); release_mem_region: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else release_region(hcd->rsrc_start, hcd->rsrc_len); clear_companion: dev_set_drvdata(&pdev->dev, NULL); usb_put_hcd(hcd); disable_pci: pci_disable_device(pdev); dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); wake_lock_destroy(&(hsic.resume_wake_lock)); wake_lock_destroy(&hsic.s3_wake_lock); return retval; }
/* * We need to register our own PCI probe function (instead of the USB core's * function) in order to create a second roothub under xHCI. */ static int xhci_ush_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; struct xhci_hcd *xhci; struct hc_driver *driver; struct usb_hcd *hcd; struct ush_hsic_pdata *hsic_pdata; hsic_pdata = dev->dev.platform_data; if (!hsic_pdata->has_modem) { dev_err(&dev->dev, "Don't match this driver\n"); return -ENODEV; } driver = (struct hc_driver *)id->driver_data; pci_dev = dev; wake_lock_init(&hsic.s3_wake_lock, WAKE_LOCK_SUSPEND, "hsic_s3_wlock"); hsic.hsic_pm_nb.notifier_call = hsic_pm_notify; usb_register_notify(&hsic.hsic_pm_nb); hsic.hsic_s3_entry_nb.notifier_call = hsic_s3_entry_notify; register_pm_notifier(&hsic.hsic_s3_entry_nb); retval = hsic_get_gpio_num(pci_dev); if (retval < 0) { dev_err(&dev->dev, "failed to get gpio value\n"); return -ENODEV; } /* AUX GPIO init */ retval = hsic_aux_gpio_init(hsic_pdata->aux_gpio); if (retval < 0) { dev_err(&dev->dev, "AUX GPIO init fail\n"); retval = -ENODEV; } /* AUX GPIO init */ retval = hsic_wakeup_gpio_init(hsic_pdata->wakeup_gpio); if (retval < 0) { dev_err(&dev->dev, "Wakeup GPIO init fail\n"); retval = -ENODEV; } wake_lock_init(&hsic.resume_wake_lock, WAKE_LOCK_SUSPEND, "hsic_aux2_wlock"); hsic.hsicdev_nb.notifier_call = hsic_notify; usb_register_notify(&hsic.hsicdev_nb); /* Register the USB 2.0 roothub. * FIXME: USB core must know to register the USB 2.0 roothub first. * This is sort of silly, because we could just set the HCD driver flags * to say USB 2.0, but I'm not sure what the implications would be in * the other parts of the HCD code. */ retval = usb_hcd_pci_probe(dev, id); if (retval) return retval; /* USB 2.0 roothub is stored in the PCI device now. */ hcd = dev_get_drvdata(&dev->dev); xhci = hcd_to_xhci(hcd); xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, pci_name(dev), hcd); if (!xhci->shared_hcd) { retval = -ENOMEM; goto dealloc_usb2_hcd; } /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset) * is called by usb_add_hcd(). */ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; if (hsic.hsic_enable_created == 0) { retval = create_device_files(dev); if (retval < 0) { dev_dbg(&dev->dev, "error create device files\n"); goto dealloc_usb2_hcd; } hsic.hsic_enable_created = 1; } if (hsic.hsic_mutex_init == 0) { mutex_init(&hsic.hsic_mutex); mutex_init(&hsic.wlock_mutex); hsic.hsic_mutex_init = 1; } if (hsic.aux_wq_init == 0) { init_waitqueue_head(&hsic.aux_wq); hsic.aux_wq_init = 1; } hsic.work_queue = create_singlethread_workqueue("hsic"); INIT_WORK(&hsic.wakeup_work, wakeup_work); INIT_DELAYED_WORK(&(hsic.hsic_aux), hsic_aux_work); retval = usb_add_hcd(xhci->shared_hcd, dev->irq, IRQF_SHARED); if (retval) goto put_usb3_hcd; /* Roothub already marked as USB 3.0 speed */ /* Enable Controller wakeup capability */ device_set_wakeup_enable(&dev->dev, true); pm_runtime_set_active(&dev->dev); /* Check here to avoid to call pm_runtime_put_noidle() twice */ if (!pci_dev_run_wake(dev)) pm_runtime_put_noidle(&dev->dev); pm_runtime_allow(&dev->dev); hsic.port_disconnect = 0; hsic_enable = 1; hsic.s3_rt_state = RESUMED; s3_wake_lock(); return 0; put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); dealloc_usb2_hcd: usb_hcd_pci_remove(dev); wake_lock_destroy(&(hsic.resume_wake_lock)); wake_lock_destroy(&hsic.s3_wake_lock); return retval; }
static int baseband_xmm_power_driver_probe(struct platform_device *device) { struct baseband_power_platform_data *data = (struct baseband_power_platform_data *) device->dev.platform_data; struct device *dev = &device->dev; unsigned long flags; int err; pr_debug("%s\n", __func__); pr_debug("[XMM] enum_delay_ms=%ld\n", enum_delay_ms); /* check for platform data */ if (!data) return -ENODEV; /* check if supported modem */ if (data->baseband_type != BASEBAND_XMM) { pr_err("unsuppported modem\n"); return -ENODEV; } /* save platform data */ baseband_power_driver_data = data; /* create device file */ err = device_create_file(dev, &dev_attr_xmm_onoff); if (err < 0) { pr_err("%s - device_create_file failed\n", __func__); return -ENODEV; } /* init wake lock */ wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "baseband_xmm_power"); /* init spin lock */ spin_lock_init(&xmm_lock); /* request baseband gpio(s) */ tegra_baseband_gpios[0].gpio = baseband_power_driver_data ->modem.xmm.bb_rst; tegra_baseband_gpios[1].gpio = baseband_power_driver_data ->modem.xmm.bb_on; tegra_baseband_gpios[2].gpio = baseband_power_driver_data ->modem.xmm.ipc_bb_wake; tegra_baseband_gpios[3].gpio = baseband_power_driver_data ->modem.xmm.ipc_ap_wake; tegra_baseband_gpios[4].gpio = baseband_power_driver_data ->modem.xmm.ipc_hsic_active; tegra_baseband_gpios[5].gpio = baseband_power_driver_data ->modem.xmm.ipc_hsic_sus_req; err = gpio_request_array(tegra_baseband_gpios, ARRAY_SIZE(tegra_baseband_gpios)); if (err < 0) { pr_err("%s - request gpio(s) failed\n", __func__); return -ENODEV; } /* request baseband irq(s) */ if (modem_flash && modem_pm) { pr_debug("%s: request_irq IPC_AP_WAKE_IRQ\n", __func__); ipc_ap_wake_state = IPC_AP_WAKE_UNINIT; err = request_threaded_irq( gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL, baseband_xmm_power_ipc_ap_wake_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "IPC_AP_WAKE_IRQ", NULL); if (err < 0) { pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n", __func__); return err; } err = enable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake)); if (err < 0) pr_err("%s: enable_irq_wake error\n", __func__); ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY; if (modem_ver >= XMM_MODEM_VER_1130) { pr_debug("%s: ver > 1130: AP_WAKE_INIT1\n", __func__); /* ver 1130 or later starts in INIT1 state */ ipc_ap_wake_state = IPC_AP_WAKE_INIT1; } } /* init work queue */ workqueue = create_singlethread_workqueue ("baseband_xmm_power_workqueue"); if (!workqueue) { pr_err("cannot create workqueue\n"); return -1; } baseband_xmm_power_work = (struct baseband_xmm_power_work_t *) kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL); if (!baseband_xmm_power_work) { pr_err("cannot allocate baseband_xmm_power_work\n"); return -1; } INIT_WORK((struct work_struct *) baseband_xmm_power_work, baseband_xmm_power_work_func); baseband_xmm_power_work->state = BBXMM_WORK_INIT; queue_work(workqueue, (struct work_struct *) baseband_xmm_power_work); /* init work objects */ INIT_WORK(&init1_work, baseband_xmm_power_init1_work); INIT_WORK(&init2_work, baseband_xmm_power_init2_work); INIT_WORK(&L2_resume_work, baseband_xmm_power_L2_resume_work); INIT_WORK(&autopm_resume_work, baseband_xmm_power_autopm_resume); /* init state variables */ register_hsic_device = true; CP_initiated_L2toL0 = false; spin_lock_irqsave(&xmm_lock, flags); baseband_xmm_powerstate = BBXMM_PS_UNINIT; wakeup_pending = false; spin_unlock_irqrestore(&xmm_lock, flags); usb_register_notify(&usb_xmm_nb); pr_debug("%s }\n", __func__); return 0; }
static ssize_t usbdev_trig_name_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct led_classdev *led_cdev = dev_get_drvdata(dev); struct usbdev_trig_data *td = led_cdev->trigger_data; if (size < 0 || size >= DEV_BUS_ID_SIZE) return -EINVAL; write_lock(&td->lock); strcpy(td->device_name, buf); if (size > 0 && td->device_name[size - 1] == '\n') td->device_name[size - 1] = 0; if (td->device_name[0] != 0) { struct usbdev_trig_match match = { .device_name = td->device_name, }; /* check for existing device to update from */ usb_for_each_dev(&match, usbdev_trig_find_usb_dev); if (match.usb_dev) { if (td->usb_dev) usb_put_dev(td->usb_dev); td->usb_dev = match.usb_dev; td->last_urbnum = atomic_read(&match.usb_dev->urbnum); } /* updates LEDs, may start timers */ usbdev_trig_update_state(td); } write_unlock(&td->lock); return size; } static DEVICE_ATTR(device_name, 0644, usbdev_trig_name_show, usbdev_trig_name_store); static ssize_t usbdev_trig_interval_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); struct usbdev_trig_data *td = led_cdev->trigger_data; read_lock(&td->lock); sprintf(buf, "%u\n", jiffies_to_msecs(td->interval)); read_unlock(&td->lock); return strlen(buf) + 1; } static ssize_t usbdev_trig_interval_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct led_classdev *led_cdev = dev_get_drvdata(dev); struct usbdev_trig_data *td = led_cdev->trigger_data; int ret = -EINVAL; char *after; unsigned long value = simple_strtoul(buf, &after, 10); size_t count = after - buf; if (*after && isspace(*after)) count++; if (count == size && value <= 10000) { write_lock(&td->lock); td->interval = msecs_to_jiffies(value); usbdev_trig_update_state(td); /* resets timer */ write_unlock(&td->lock); ret = count; } return ret; } static DEVICE_ATTR(activity_interval, 0644, usbdev_trig_interval_show, usbdev_trig_interval_store); static int usbdev_trig_notify(struct notifier_block *nb, unsigned long evt, void *data) { struct usb_device *usb_dev; struct usbdev_trig_data *td; if (evt != USB_DEVICE_ADD && evt != USB_DEVICE_REMOVE) return NOTIFY_DONE; usb_dev = data; td = container_of(nb, struct usbdev_trig_data, notifier); write_lock(&td->lock); if (strcmp(dev_name(&usb_dev->dev), td->device_name)) goto done; if (evt == USB_DEVICE_ADD) { usb_get_dev(usb_dev); if (td->usb_dev != NULL) usb_put_dev(td->usb_dev); td->usb_dev = usb_dev; td->last_urbnum = atomic_read(&usb_dev->urbnum); } else if (evt == USB_DEVICE_REMOVE) { if (td->usb_dev != NULL) { usb_put_dev(td->usb_dev); td->usb_dev = NULL; } } usbdev_trig_update_state(td); done: write_unlock(&td->lock); return NOTIFY_DONE; } /* here's the real work! */ static void usbdev_trig_timer(unsigned long arg) { struct usbdev_trig_data *td = (struct usbdev_trig_data *)arg; int new_urbnum; write_lock(&td->lock); if (!td->usb_dev || td->interval == 0) { /* * we don't need to do timer work, just reflect device presence */ if (td->usb_dev) led_set_brightness(td->led_cdev, LED_FULL); else led_set_brightness(td->led_cdev, LED_OFF); goto no_restart; } if (td->interval) new_urbnum = atomic_read(&td->usb_dev->urbnum); else new_urbnum = 0; if (td->usb_dev) { /* * Base state is ON (device is present). If there's no device, * we don't get this far and the LED is off. * OFF -> ON always * ON -> OFF on activity */ if (td->led_cdev->brightness == LED_OFF) led_set_brightness(td->led_cdev, LED_FULL); else if (td->last_urbnum != new_urbnum) led_set_brightness(td->led_cdev, LED_OFF); } else { /* * base state is OFF * ON -> OFF always * OFF -> ON on activity */ if (td->led_cdev->brightness == LED_FULL) led_set_brightness(td->led_cdev, LED_OFF); else if (td->last_urbnum != new_urbnum) led_set_brightness(td->led_cdev, LED_FULL); } td->last_urbnum = new_urbnum; mod_timer(&td->timer, jiffies + td->interval); no_restart: write_unlock(&td->lock); } static void usbdev_trig_activate(struct led_classdev *led_cdev) { struct usbdev_trig_data *td; int rc; td = kzalloc(sizeof(struct usbdev_trig_data), GFP_KERNEL); if (!td) return; rwlock_init(&td->lock); td->notifier.notifier_call = usbdev_trig_notify; td->notifier.priority = 10; setup_timer(&td->timer, usbdev_trig_timer, (unsigned long) td); td->led_cdev = led_cdev; td->interval = msecs_to_jiffies(50); led_cdev->trigger_data = td; rc = device_create_file(led_cdev->dev, &dev_attr_device_name); if (rc) goto err_out; rc = device_create_file(led_cdev->dev, &dev_attr_activity_interval); if (rc) goto err_out_device_name; usb_register_notify(&td->notifier); return; err_out_device_name: device_remove_file(led_cdev->dev, &dev_attr_device_name); err_out: led_cdev->trigger_data = NULL; kfree(td); } static void usbdev_trig_deactivate(struct led_classdev *led_cdev) { struct usbdev_trig_data *td = led_cdev->trigger_data; if (td) { usb_unregister_notify(&td->notifier); device_remove_file(led_cdev->dev, &dev_attr_device_name); device_remove_file(led_cdev->dev, &dev_attr_activity_interval); write_lock(&td->lock); if (td->usb_dev) { usb_put_dev(td->usb_dev); td->usb_dev = NULL; } write_unlock(&td->lock); del_timer_sync(&td->timer); kfree(td); } } static struct led_trigger usbdev_led_trigger = { .name = "usbdev", .activate = usbdev_trig_activate, .deactivate = usbdev_trig_deactivate, }; static int __init usbdev_trig_init(void) { return led_trigger_register(&usbdev_led_trigger); } static void __exit usbdev_trig_exit(void) { led_trigger_unregister(&usbdev_led_trigger); } module_init(usbdev_trig_init); module_exit(usbdev_trig_exit); MODULE_AUTHOR("Gabor Juhos <*****@*****.**>"); MODULE_DESCRIPTION("USB device LED trigger"); MODULE_LICENSE("GPL v2");
static int baseband_xmm_power_driver_probe(struct platform_device *device) { struct baseband_power_platform_data *data = (struct baseband_power_platform_data *) device->dev.platform_data; struct device *dev = &device->dev; unsigned long flags; int err, i; int ap_wake_irq; pr_info("%s\n", __func__); pr_info("[XMM] enum_delay_ms=%ld\n", enum_delay_ms); /* check for platform data */ if (!data) return -ENODEV; /* check if supported modem */ if (data->baseband_type != BASEBAND_XMM) { pr_err("unsuppported modem\n"); return -ENODEV; } /* save platform data */ baseband_power_driver_data = data; /* create device file */ /*err = device_create_file(dev, &dev_attr_xmm_onoff); if (err < 0) { pr_err("%s - device_create_file failed\n", __func__); return -ENODEV; }*/ /* init wake lock */ wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "baseband_xmm_power"); wake_lock_init(&modem_recovery_wakelock, WAKE_LOCK_SUSPEND, "modem_recovery"); /* init spin lock */ spin_lock_init(&xmm_lock); /* request baseband gpio(s) */ tegra_baseband_gpios[0].gpio = baseband_power_driver_data ->modem.xmm.bb_rst; tegra_baseband_gpios[1].gpio = baseband_power_driver_data ->modem.xmm.bb_on; tegra_baseband_gpios[2].gpio = baseband_power_driver_data ->modem.xmm.ipc_bb_wake; tegra_baseband_gpios[3].gpio = baseband_power_driver_data ->modem.xmm.ipc_ap_wake; tegra_baseband_gpios[4].gpio = baseband_power_driver_data ->modem.xmm.ipc_hsic_active; tegra_baseband_gpios[5].gpio = baseband_power_driver_data ->modem.xmm.ipc_hsic_sus_req; tegra_baseband_gpios[6].gpio = baseband_power_driver_data ->modem.xmm.bb_vbat; tegra_baseband_gpios[7].gpio = baseband_power_driver_data ->modem.xmm.ipc_bb_rst_ind; tegra_baseband_gpios[8].gpio = baseband_power_driver_data ->modem.xmm.ipc_bb_force_crash; err = gpio_request_array(tegra_baseband_gpios, ARRAY_SIZE(tegra_baseband_gpios)); if (err < 0) { pr_err("%s - request gpio(s) failed\n", __func__); return -ENODEV; } /* location is at /sys/devices/platform/baseband_xmm_power */ for (i = 0; i < (ARRAY_SIZE(xmm_device_attr) - 1); i++) { err = device_create_file(dev, &xmm_device_attr[i]); if (err) { pr_err("create file %d failed, err = %d\n", i, err); goto failed_create_file; } } /* get regulator LDO7 for hsic power */ if (!reg_grouper_hsic) { reg_grouper_hsic = regulator_get(NULL, "vddio_hsic"); if (IS_ERR_OR_NULL(reg_grouper_hsic)) { pr_err("grouper 3G HSIC power on LDO7 failed\n"); reg_grouper_hsic = NULL; return PTR_ERR(reg_grouper_hsic); } regulator_set_voltage(reg_grouper_hsic, 1200000, 1200000); } /* request baseband irq(s) */ if (modem_flash && modem_pm) { pr_debug("%s: request_irq IPC_AP_WAKE_IRQ\n", __func__); ipc_ap_wake_state = IPC_AP_WAKE_UNINIT; err = request_threaded_irq( gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL, baseband_xmm_power_ipc_ap_wake_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "IPC_AP_WAKE_IRQ", NULL); if (err < 0) { pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n", __func__); return err; } ap_wake_irq = enable_irq_wake(gpio_to_irq(data->modem.xmm.ipc_ap_wake)); tegra_pm_irq_set_wake_type(ap_wake_irq, IRQF_TRIGGER_FALLING); enable_irq_wake(ap_wake_irq); if (err < 0) pr_err("%s: enable_irq_wake error\n", __func__); ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY; if (modem_ver >= XMM_MODEM_VER_1130) { pr_debug("%s: ver > 1130: AP_WAKE_INIT1\n", __func__); /* ver 1130 or later starts in INIT1 state */ ipc_ap_wake_state = IPC_AP_WAKE_INIT1; } } /* init work queue */ workqueue = create_singlethread_workqueue ("baseband_xmm_power_workqueue"); if (!workqueue) { pr_err("cannot create workqueue\n"); return -1; } baseband_xmm_power_work = (struct baseband_xmm_power_work_t *) kmalloc(sizeof(struct baseband_xmm_power_work_t), GFP_KERNEL); if (!baseband_xmm_power_work) { pr_err("cannot allocate baseband_xmm_power_work\n"); return -1; } INIT_WORK((struct work_struct *) baseband_xmm_power_work, baseband_xmm_power_work_func); baseband_xmm_power_work->state = BBXMM_WORK_INIT; queue_work(workqueue, (struct work_struct *) baseband_xmm_power_work); /* init work objects */ INIT_WORK(&init1_work, baseband_xmm_power_init1_work); INIT_WORK(&init2_work, baseband_xmm_power_init2_work); INIT_WORK(&L2_resume_work, baseband_xmm_power_L2_resume_work); INIT_WORK(&autopm_resume_work, baseband_xmm_power_autopm_resume); /* init state variables */ register_hsic_device = true; CP_initiated_L2toL0 = false; spin_lock_irqsave(&xmm_lock, flags); baseband_xmm_powerstate = BBXMM_PS_UNINIT; wakeup_pending = false; spin_unlock_irqrestore(&xmm_lock, flags); usb_register_notify(&usb_xmm_nb); pr_debug("%s }\n", __func__); return 0; failed_create_file: while (i--) device_remove_file(dev, &xmm_device_attr[i]); return err; }
/** * dwc3_otg_start_host - helper function for starting/stoping the host controller driver. * * @otg: Pointer to the otg_transceiver structure. * @on: start / stop the host controller driver. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; struct usb_hcd *hcd; int ret = 0; if (!dwc->xhci) return -EINVAL; if (!dotg->vbus_otg) { dotg->vbus_otg = devm_regulator_get(dwc->dev->parent, "vbus_dwc3"); if (IS_ERR(dotg->vbus_otg)) { dev_err(dwc->dev, "Failed to get vbus regulator\n"); ret = PTR_ERR(dotg->vbus_otg); dotg->vbus_otg = 0; return ret; } } if (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); dwc3_otg_notify_host_mode(otg, on); usb_phy_notify_connect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); /* register ocp notification */ if (ext_xceiv && ext_xceiv->ext_ocp_notification.notify) { ret = regulator_register_ocp_notification( dotg->vbus_otg, &ext_xceiv->ext_ocp_notification); if (ret) dev_err(otg->phy->dev, "unable to register ocp\n"); } ret = regulator_enable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to enable vbus_otg\n"); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* The delay between enabling regulator and adding the platform device is needed to succeed in the enumeration for certain devices. */ usleep(10000); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is * enabled for xhci device. Due to this, disable_depth becomes * greater than one and runtimepm is not enabled for next microA * connect. Fix this by calling pm_runtime_init for xhci device. */ pm_runtime_init(&dwc->xhci->dev); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); regulator_disable(dotg->vbus_otg); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* * WORKAROUND: avoids entering a suspend state, because PMIC * is damaged by known issue when attempt to suspend. */ wake_lock(&dotg->host_wakelock); /* * WORKAROUND: currently host mode suspend isn't working well. * Disable xHCI's runtime PM for now. */ pm_runtime_disable(&dwc->xhci->dev); if (no_device_timeout_enable) { dotg->no_device_timeout_enabled = 1; dotg->device_count = 0; dotg->retry_count = 0; dotg->usbdev_nb.notifier_call = dwc3_usbdev_notify; usb_register_notify(&dotg->usbdev_nb); dwc3_otg_start_no_device_work(dotg, true); } hcd = platform_get_drvdata(dwc->xhci); otg->host = &hcd->self; dwc3_gadget_usb3_phy_suspend(dwc, true); } else { dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__); ret = regulator_disable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to disable vbus_otg\n"); return ret; } dbg_event(0xFF, "StHost get", 0); /* unregister ocp notification */ if (ext_xceiv && ext_xceiv->ext_ocp_notification.notify) { ret = regulator_register_ocp_notification( dotg->vbus_otg, NULL); if (ret) dev_err(otg->phy->dev, "unable to unregister ocp\n"); } pm_runtime_get(dwc->dev); usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); dwc3_otg_notify_host_mode(otg, on); otg->host = NULL; if (dotg->no_device_timeout_enabled) { dotg->no_device_timeout_enabled = 0; dwc3_otg_start_no_device_work(dotg, false); usb_unregister_notify(&dotg->usbdev_nb); } platform_device_del(dwc->xhci); /* WORKAROUND: delays execution of the block-reset because it * causes HWWD if ext_xceive access the HW during block reset. */ usleep(10000); if (wake_lock_active(&dotg->host_wakelock)) wake_unlock(&dotg->host_wakelock); /* * Perform USB hardware RESET (both core reset and DBM reset) * when moving from host to peripheral. This is required for * peripheral mode to work. */ if (ext_xceiv && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, true); dwc3_gadget_usb3_phy_suspend(dwc, false); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); /* re-init core and OTG registers as block reset clears these */ dwc3_post_host_reset_core_init(dwc); dbg_event(0xFF, "StHost put", 0); pm_runtime_put(dwc->dev); } return 0; }