Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
static int __init my_init (void)
{
    usb_register_notify (&my_nh_block);
    printk (KERN_INFO "USB Notifier module successfully loaded\n");

    return 0;
}
Exemplo n.º 3
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);
}
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
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;
}
Exemplo n.º 12
0
/**
 * 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;
}