Пример #1
0
static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
{
	struct nop_usb_xceiv	*nop;
	int err;

	nop = kzalloc(sizeof *nop, GFP_KERNEL);
	if (!nop)
		return -ENOMEM;

	nop->dev		= &pdev->dev;
	nop->otg.dev		= nop->dev;
	nop->otg.label		= "nop-xceiv";
	nop->otg.state		= OTG_STATE_UNDEFINED;
	nop->otg.set_host	= nop_set_host;
	nop->otg.set_peripheral	= nop_set_peripheral;
	nop->otg.set_suspend	= nop_set_suspend;
	nop->otg.id		= pdev->id;

	err = otg_set_transceiver(&nop->otg);
	if (err) {
		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
			err);
		goto exit;
	}

	platform_set_drvdata(pdev, nop);

	ATOMIC_INIT_NOTIFIER_HEAD(&nop->otg.notifier);

	return 0;
exit:
	kfree(nop);
	return err;
}
Пример #2
0
static int __init msm_cpuidle_early_init(void)
{
#ifdef CONFIG_MSM_SLEEP_STATS
	unsigned int cpu;

	for_each_possible_cpu(cpu)
		ATOMIC_INIT_NOTIFIER_HEAD(&per_cpu(msm_cpuidle_notifiers, cpu));
#endif
	return 0;
}
Пример #3
0
static int mxs_phy_probe(struct platform_device *pdev)
{
	struct resource *res;
	void __iomem *base;
	struct clk *clk;
	struct mxs_phy *mxs_phy;
	int ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "can't get device resources\n");
		return -ENOENT;
	}

	base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(base))
		return PTR_ERR(base);

	clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(clk)) {
		dev_err(&pdev->dev,
			"can't get the clock, err=%ld", PTR_ERR(clk));
		return PTR_ERR(clk);
	}

	mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
	if (!mxs_phy) {
		dev_err(&pdev->dev, "Failed to allocate USB PHY structure!\n");
		return -ENOMEM;
	}

	mxs_phy->phy.io_priv		= base;
	mxs_phy->phy.dev		= &pdev->dev;
	mxs_phy->phy.label		= DRIVER_NAME;
	mxs_phy->phy.init		= mxs_phy_init;
	mxs_phy->phy.shutdown		= mxs_phy_shutdown;
	mxs_phy->phy.set_suspend	= mxs_phy_suspend;
	mxs_phy->phy.notify_connect	= mxs_phy_on_connect;
	mxs_phy->phy.notify_disconnect	= mxs_phy_on_disconnect;

	ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier);

	mxs_phy->clk = clk;

	platform_set_drvdata(pdev, &mxs_phy->phy);

	ret = usb_add_phy_dev(&mxs_phy->phy);
	if (ret)
		return ret;

	return 0;
}
Пример #4
0
int ocmem_notifier_init(void)
{
	int id;
	/* Maximum notifiers for each subsystem */
	notifier_threshold = 1;
	mutex_lock(&nc_lock);
	for (id = 0; id < OCMEM_CLIENT_MAX; id++) {
		notifiers[id].owner = id;
		ATOMIC_INIT_NOTIFIER_HEAD(&notifiers[id].nc);
		notifiers[id].listeners = 0;
	}
	mutex_unlock(&nc_lock);
	return 0;
}
Пример #5
0
static int __init opal_message_init(void)
{
	int ret, i;

	for (i = 0; i < OPAL_MSG_TYPE_MAX; i++)
		ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]);

	ret = opal_notifier_register(&opal_message_nb);
	if (ret) {
		pr_err("%s: Can't register OPAL event notifier (%d)\n",
		       __func__, ret);
		return ret;
	}
	return 0;
}
//init function for switch_usb_class mode
static int __init switch_usb_class_init(void)
{
    int ret = 0;
    struct switch_usb_info *sui;

    hwlog_info("%s: ------entry.\n", __func__);
    ret = platform_driver_register(&usb_switch_driver);

    if(NULL == p_switch_usb_info)
	{
		sui = kzalloc(sizeof(struct switch_usb_info), GFP_KERNEL);
		if(NULL == sui) {
			pr_err("kzalloc failed!\n");
			return -ENOMEM;
		}
		p_switch_usb_info = sui;
		ATOMIC_INIT_NOTIFIER_HEAD(&sui->charger_type_notifier_head);
		spin_lock_init(&sui->reg_flag_lock);
	}

    hwlog_info("%s: ------end. ret=%d\n", __func__, ret);

    return ret;
}
Пример #7
0
static int __devinit archos_twl6030_usb_probe(struct platform_device *pdev)
{
	struct archos_twl6030_usb	*twl;
	int			status, err;
	struct twl4030_usb_data *pdata;
	struct device *dev = &pdev->dev;
	pdata = dev->platform_data;

	twl = kzalloc(sizeof *twl, GFP_KERNEL);
	if (!twl)
		return -ENOMEM;

	twl->dev		= &pdev->dev;
	twl->irq1		= platform_get_irq(pdev, 0);
	twl->irq2		= platform_get_irq(pdev, 1);
	twl->otg.dev		= twl->dev;
	twl->otg.label		= "twl6030";
	twl->otg.set_host	= archos_twl6030_set_host;
	twl->otg.set_peripheral	= archos_twl6030_set_peripheral;
	twl->asleep		= 1;
	twl->otg.set_vbus	= archos_twl6030_set_vbus;
	twl->otg.init           = archos_twl6030_phy_init;
	twl->otg.shutdown       = archos_twl6030_phy_shutdown;
	twl->otg.enable_irq	= archos_twl6030_enable_irq;
	twl->features		= pdata->features;
	
	twl->state = STATE_UNKNOWN;

	/* init spinlock for workqueue */
	spin_lock_init(&twl->lock);

	err = archos_twl6030_usb_ldo_init(twl);
	if (err) {
		dev_err(&pdev->dev, "ldo init failed\n");
		kfree(twl);
		return err;
	}

	platform_set_drvdata(pdev, twl);
	if (device_create_file(&pdev->dev, &dev_attr_vbus))
		dev_warn(&pdev->dev, "could not create sysfs file\n");

	ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);

	twl->irq_enabled = true;
	status = request_irq(twl->irq1, archos_twl6030_usbotg_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"archos_twl6030_usb", twl);
	if (status < 0) {
		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq1, status);
		device_remove_file(twl->dev, &dev_attr_vbus);
		kfree(twl);
		return status;
	}

	status = request_irq(twl->irq2, archos_twl6030_usb_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"archos_twl6030_usb", twl);
	if (status < 0) {
		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq2, status);
		free_irq(twl->irq1, twl);
		device_remove_file(twl->dev, &dev_attr_vbus);
		kfree(twl);
		return status;
	}

	INIT_DELAYED_WORK(&twl->work, linkstat_work);
	
	/* only active when a gadget is registered */
	err = otg_set_transceiver(&twl->otg);
	if (err) {
		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
			err);
		goto err_otg;
	}

	twl->vbus_draw = regulator_get(&pdev->dev, "vbus_musb");
	if (IS_ERR(twl->vbus_draw)) {
		dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
			PTR_ERR(twl->vbus_draw));
		twl->vbus_draw = NULL;
		goto err_otg;
	}

	/* initialize switches */
	twl->usb_switch.name = USB_SW_NAME;
	twl->usb_switch.print_name = usb_switch_print_name;
	twl->usb_switch.print_state = usb_switch_print_state;
	if (switch_dev_register(&twl->usb_switch) < 0) {
		dev_err(&pdev->dev, "Error creating USB switch\n");
		goto err_switch;
	}

	twl->asleep = 0;
	pdata->phy_init(dev);
	archos_twl6030_enable_irq(&twl->otg);
	
	dev_err(&pdev->dev, "Initialized Archos TWL6030 USB module\n");
	return 0;
err_switch:
	regulator_put(twl->vbus_draw);
err_otg:
	device_remove_file(twl->dev, &dev_attr_vbus);
	free_irq(twl->irq1, twl);
	free_irq(twl->irq2, twl);
	kfree(twl);
	return err;
}
static int cpcap_otg_probe(struct platform_device *pdev)
{
	struct cpcap_otg_data *cpcap;
	struct resource *res;
	unsigned long val;
	int err;

	cpcap = kzalloc(sizeof(struct cpcap_otg_data), GFP_KERNEL);
	if (!cpcap)
		return -ENOMEM;

	cpcap->otg.dev = &pdev->dev;
	cpcap->otg.label = "cpcap-otg";
	cpcap->otg.state = OTG_STATE_UNDEFINED;
	cpcap->otg.set_host = cpcap_otg_set_host;
	cpcap->otg.set_peripheral = cpcap_otg_set_peripheral;
	cpcap->otg.set_suspend = cpcap_otg_set_suspend;
	cpcap->otg.set_power = cpcap_otg_set_power;
	cpcap->host = pdev->dev.platform_data;
	wake_lock_init(&cpcap->wake_lock, WAKE_LOCK_SUSPEND, "cpcap_otg");

	platform_set_drvdata(pdev, cpcap);

	cpcap->clk = clk_get(&pdev->dev, NULL);
	if (IS_ERR(cpcap->clk)) {
		dev_err(&pdev->dev, "Can't get otg clock\n");
		err = PTR_ERR(cpcap->clk);
		goto err_clk;
	}

	err = clk_enable(cpcap->clk);
	if (err)
		goto err_clken;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "Failed to get I/O memory\n");
		err = -ENXIO;
		goto err_io;
	}
	cpcap->regs = ioremap(res->start, resource_size(res));
	if (!cpcap->regs) {
		err = -ENOMEM;
		goto err_io;
	}

	val = readl(cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);
	val |= TEGRA_VBUS_WAKEUP_SW_ENABLE | TEGRA_ID_SW_ENABLE;
	val |= TEGRA_ID_SW_VALUE;
	val &= ~(TEGRA_VBUS_WAKEUP_SW_VALUE);
	writel(val, cpcap->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET);

	clk_disable(cpcap->clk);
	cpcap->otg.state = OTG_STATE_A_SUSPEND;

	ATOMIC_INIT_NOTIFIER_HEAD(&cpcap->otg.notifier);
	cpcap->nb.notifier_call = cpcap_otg_notify;
	otg_register_notifier(&cpcap->otg, &cpcap->nb);

	err = otg_set_transceiver(&cpcap->otg);
	if (err) {
		dev_err(&pdev->dev, "can't register transceiver (%d)\n", err);
		goto err_otg;
	}

	return 0;

err_otg:
	iounmap(cpcap->regs);
err_io:
	clk_disable(cpcap->clk);
err_clken:
	clk_put(cpcap->clk);
err_clk:
	wake_lock_destroy(&cpcap->wake_lock);
	platform_set_drvdata(pdev, NULL);
	kfree(cpcap);
	return err;
}
Пример #9
0
static int twl4030_usb_probe(struct platform_device *pdev)
{
	struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev);
	struct twl4030_usb	*twl;
	struct phy		*phy;
	int			status, err;
	struct usb_otg		*otg;
	struct device_node	*np = pdev->dev.of_node;
	struct phy_provider	*phy_provider;
	struct phy_init_data	*init_data = NULL;

	twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
	if (!twl)
		return -ENOMEM;

	if (np)
		of_property_read_u32(np, "usb_mode",
				(enum twl4030_usb_mode *)&twl->usb_mode);
	else if (pdata) {
		twl->usb_mode = pdata->usb_mode;
		init_data = pdata->init_data;
	} else {
		dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
		return -EINVAL;
	}

	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
	if (!otg)
		return -ENOMEM;

	twl->dev		= &pdev->dev;
	twl->irq		= platform_get_irq(pdev, 0);
	twl->vbus_supplied	= false;
	twl->asleep		= 1;
	twl->linkstat		= OMAP_MUSB_UNKNOWN;

	twl->phy.dev		= twl->dev;
	twl->phy.label		= "twl4030";
	twl->phy.otg		= otg;
	twl->phy.type		= USB_PHY_TYPE_USB2;

	otg->phy		= &twl->phy;
	otg->set_host		= twl4030_set_host;
	otg->set_peripheral	= twl4030_set_peripheral;

	phy = devm_phy_create(twl->dev, NULL, &ops, init_data);
	if (IS_ERR(phy)) {
		dev_dbg(&pdev->dev, "Failed to create PHY\n");
		return PTR_ERR(phy);
	}

	phy_set_drvdata(phy, twl);

	phy_provider = devm_of_phy_provider_register(twl->dev,
		of_phy_simple_xlate);
	if (IS_ERR(phy_provider))
		return PTR_ERR(phy_provider);

	/* init spinlock for workqueue */
	spin_lock_init(&twl->lock);

	INIT_DELAYED_WORK(&twl->id_workaround_work, twl4030_id_workaround_work);

	err = twl4030_usb_ldo_init(twl);
	if (err) {
		dev_err(&pdev->dev, "ldo init failed\n");
		return err;
	}
	usb_add_phy_dev(&twl->phy);

	platform_set_drvdata(pdev, twl);
	if (device_create_file(&pdev->dev, &dev_attr_vbus))
		dev_warn(&pdev->dev, "could not create sysfs file\n");

	ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);

	/* Our job is to use irqs and status from the power module
	 * to keep the transceiver disabled when nothing's connected.
	 *
	 * FIXME we actually shouldn't start enabling it until the
	 * USB controller drivers have said they're ready, by calling
	 * set_host() and/or set_peripheral() ... OTG_capable boards
	 * need both handles, otherwise just one suffices.
	 */
	twl->irq_enabled = true;
	status = devm_request_threaded_irq(twl->dev, twl->irq, NULL,
			twl4030_usb_irq, IRQF_TRIGGER_FALLING |
			IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_usb", twl);
	if (status < 0) {
		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq, status);
		return status;
	}

	dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
	return 0;
}
static int __devinit twl4030_usb_probe(struct platform_device *pdev)
{
	struct twl4030_usb_data *pdata = pdev->dev.platform_data;
	struct twl4030_usb	*twl;
	int			status, err;
	struct usb_otg		*otg;

	if (!pdata) {
		dev_dbg(&pdev->dev, "platform_data not available\n");
		return -EINVAL;
	}

	twl = kzalloc(sizeof *twl, GFP_KERNEL);
	if (!twl)
		return -ENOMEM;

	otg = kzalloc(sizeof *otg, GFP_KERNEL);
	if (!otg) {
		kfree(twl);
		return -ENOMEM;
	}

	twl->dev		= &pdev->dev;
	twl->irq		= platform_get_irq(pdev, 0);
	twl->usb_mode		= pdata->usb_mode;
	twl->vbus_supplied	= false;
	twl->asleep		= 1;

	twl->phy.dev		= twl->dev;
	twl->phy.label		= "twl4030";
	twl->phy.otg		= otg;
	twl->phy.set_suspend	= twl4030_set_suspend;

	otg->phy		= &twl->phy;
	otg->set_host		= twl4030_set_host;
	otg->set_peripheral	= twl4030_set_peripheral;

	
	spin_lock_init(&twl->lock);

	err = twl4030_usb_ldo_init(twl);
	if (err) {
		dev_err(&pdev->dev, "ldo init failed\n");
		kfree(otg);
		kfree(twl);
		return err;
	}
	usb_set_transceiver(&twl->phy);

	platform_set_drvdata(pdev, twl);
	if (device_create_file(&pdev->dev, &dev_attr_vbus))
		dev_warn(&pdev->dev, "could not create sysfs file\n");

	ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);

	twl->irq_enabled = true;
	status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"twl4030_usb", twl);
	if (status < 0) {
		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq, status);
		kfree(otg);
		kfree(twl);
		return status;
	}

	twl4030_usb_phy_init(twl);

	dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
	return 0;
}
Пример #11
0
static int __devinit twl6030_usb_probe(struct platform_device *pdev)
{
	struct twl6030_usb	*twl;
	int			status, err;
	struct twl4030_usb_data *pdata;
	struct device *dev = &pdev->dev;
	pdata = dev->platform_data;

	twl = kzalloc(sizeof *twl, GFP_KERNEL);
	if (!twl)
		return -ENOMEM;

	twl->dev		= &pdev->dev;
	twl->irq1		= platform_get_irq(pdev, 0);
	twl->irq2		= platform_get_irq(pdev, 1);
	twl->features		= pdata->features;
	twl->otg.dev		= twl->dev;
	twl->otg.label		= "twl6030";
	twl->otg.set_host	= twl6030_set_host;
	twl->otg.set_peripheral	= twl6030_set_peripheral;
	twl->otg.set_vbus	= twl6030_set_vbus;
	twl->otg.init		= twl6030_phy_init;
	twl->otg.shutdown	= twl6030_phy_shutdown;
	twl->otg.set_suspend	= twl6030_phy_suspend;
	twl->otg.start_srp	= twl6030_start_srp;

	/* init spinlock for workqueue */
	spin_lock_init(&twl->lock);

	err = twl6030_usb_ldo_init(twl);
	if (err) {
		dev_err(&pdev->dev, "ldo init failed\n");
		kfree(twl);
		return err;
	}
	otg_set_transceiver(&twl->otg);

	platform_set_drvdata(pdev, twl);
	if (device_create_file(&pdev->dev, &dev_attr_vbus))
		dev_warn(&pdev->dev, "could not create sysfs file\n");

	ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);

	INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);

	twl->irq_enabled = true;
	status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"twl6030_usb", twl);
	if (status < 0) {
		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq1, status);
		device_remove_file(twl->dev, &dev_attr_vbus);
		kfree(twl);
		return status;
	}

	status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"twl6030_usb", twl);
	if (status < 0) {
		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq2, status);
		free_irq(twl->irq1, twl);
		device_remove_file(twl->dev, &dev_attr_vbus);
		kfree(twl);
		return status;
	}

	twl->asleep = 0;
	pdata->phy_init(dev);
	twl6030_phy_suspend(&twl->otg, 0);
	twl6030_enable_irq(&twl->otg);
	dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");

	return 0;
}
Пример #12
0
static struct dwc_otg2 *dwc3_otg_alloc(struct device *dev)
{
	struct dwc_otg2 *otg = NULL;
	struct usb_phy *usb_phy;
	int retval;

	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
	if (!otg) {
		dev_err(dev, "Alloc otg failed\n");
		return NULL;
	}

	the_transceiver = otg;
	otg->otg_data = dev->platform_data;

	usb_phy = &otg->usb2_phy;
	otg->otg.phy = usb_phy;
	otg->usb2_phy.otg = &otg->otg;

	otg->dev		= dev;
	otg->usb3_phy.dev		= otg->dev;
	otg->usb3_phy.label		= "dwc-usb3-phy";
	otg->usb3_phy.state		= OTG_STATE_UNDEFINED;
	otg->usb3_phy.otg	= &otg->otg;
	otg->usb2_phy.dev		= otg->dev;
	otg->usb2_phy.label		= "dwc-usb2-phy";
	otg->usb2_phy.state		= OTG_STATE_UNDEFINED;
	otg->usb2_phy.set_power	= dwc3_otg_pdata->set_power;
	otg->usb2_phy.get_chrg_status	= dwc_otg_get_chrg_status;
	otg->usb2_phy.io_ops = &dwc_otg_io_ops;
	otg->usb2_phy.otg	= &otg->otg;
	otg->otg.set_host	= dwc_otg2_set_host;
	otg->otg.set_peripheral	= dwc_otg2_set_peripheral;
	ATOMIC_INIT_NOTIFIER_HEAD(&otg->usb2_phy.notifier);
	ATOMIC_INIT_NOTIFIER_HEAD(&otg->usb3_phy.notifier);

	otg->state = DWC_STATE_B_IDLE;
	spin_lock_init(&otg->lock);
	init_waitqueue_head(&otg->main_wq);

	/* Register otg notifier to monitor ID and VBus change events */
	otg->nb.notifier_call = dwc_otg_handle_notification;
	usb_register_notifier(&otg->usb2_phy, &otg->nb);

	otg_dbg(otg, "Version: %s\n", VERSION);
	retval = usb_add_phy(&otg->usb2_phy, USB_PHY_TYPE_USB2);
	if (retval) {
		otg_err(otg, "can't register transceiver, err: %d\n",
			retval);
		goto err1;
	}

	retval = usb_add_phy(&otg->usb3_phy, USB_PHY_TYPE_USB3);
	if (retval) {
		otg_err(otg, "can't register transceiver, err: %d\n",
			retval);
		goto err2;
	}

	return otg;

err2:
	usb_remove_phy(&otg->usb2_phy);

err1:
	kfree(otg);
	otg = NULL;

	return otg;
}
Пример #13
0
static int __devinit bcmpmu_otg_xceiv_probe(struct platform_device *pdev)
{
    int error = 0;
    struct bcmpmu_otg_xceiv_data *xceiv_data;
    struct bcmpmu *bcmpmu = pdev->dev.platform_data;

    dev_info(&pdev->dev, "Probing started...\n");

    xceiv_data = kzalloc(sizeof(*xceiv_data), GFP_KERNEL);
    if (!xceiv_data) {
        dev_warn(&pdev->dev, "Memory allocation failed\n");
        return -ENOMEM;
    }

    /* REVISIT: Currently there isn't a way to obtain
     * regulator string associated with USB. Hardcode for now
     */
    xceiv_data->bcm_hsotg_regulator =
        regulator_get(NULL, "usbldo_uc");

    if (IS_ERR(xceiv_data->bcm_hsotg_regulator)) {
        dev_warn(&pdev->dev, "Failed to get regulator handle\n");
        kfree(xceiv_data);
        return -ENODEV;
    }

    /* Enable USB LDO */
    regulator_enable(xceiv_data->bcm_hsotg_regulator);
    xceiv_data->regulator_enabled = true;
    /* Give 2ms to ramp up USBLDO */
    mdelay(USBLDO_RAMP_UP_DELAY_IN_MS);
    xceiv_data->dev = &pdev->dev;
    xceiv_data->bcmpmu = bcmpmu;
    xceiv_data->otg_xceiver.xceiver.dev = xceiv_data->dev;
    xceiv_data->otg_xceiver.xceiver.label = "bcmpmu_otg_xceiv";
    xceiv_data->host = false;
    xceiv_data->vbus_enabled = false;

    /* Create a work queue for OTG work items */
    xceiv_data->bcm_otg_work_queue = create_workqueue("bcm_otg_events");
    if (xceiv_data->bcm_otg_work_queue == NULL) {
        dev_warn(&pdev->dev,
                 "BCM OTG events work queue creation failed\n");
        bcmpmu_otg_free_regulator(xceiv_data);
        kfree(xceiv_data);
        return -ENOMEM;
    }

    /* Create one work item per deferrable function */
    INIT_WORK(&xceiv_data->bcm_otg_vbus_invalid_work,
              bcmpmu_otg_xceiv_vbus_invalid_handler);
    INIT_WORK(&xceiv_data->bcm_otg_vbus_valid_work,
              bcmpmu_otg_xceiv_vbus_valid_handler);
    INIT_WORK(&xceiv_data->bcm_otg_vbus_a_invalid_work,
              bcmpmu_otg_xceiv_vbus_a_invalid_handler);
    INIT_WORK(&xceiv_data->bcm_otg_vbus_a_valid_work,
              bcmpmu_otg_xceiv_vbus_a_valid_handler);
    INIT_WORK(&xceiv_data->bcm_otg_id_status_change_work,
              bcmpmu_otg_xceiv_id_change_handler);
    INIT_WORK(&xceiv_data->bcm_otg_chg_detect_work,
              bcmpmu_otg_xceiv_chg_detect_handler);
    INIT_WORK(&xceiv_data->bcm_otg_sess_end_srp_work,
              bcmpmu_otg_xceiv_sess_end_srp_handler);
    INIT_DELAYED_WORK(&xceiv_data->bcm_otg_delayed_adp_work,
                      bcmpmu_otg_xceiv_delayed_adp_handler);

    /* Initial value for previous OTG ID value.
     * 0 means unsupported
     */
    xceiv_data->prev_otg_id = 0;

    /* Charger type not known yet */
    xceiv_data->usb_charger_type = PMU_USB_TYPE_NONE;

    xceiv_data->otg_xceiver.xceiver.state = OTG_STATE_UNDEFINED;
    xceiv_data->otg_xceiver.xceiver.set_vbus =
        bcmpmu_otg_xceiv_set_vbus;
    xceiv_data->otg_xceiver.xceiver.set_peripheral =
        bcmpmu_otg_xceiv_set_peripheral;
    xceiv_data->otg_xceiver.xceiver.set_host =
        bcmpmu_otg_xceiv_set_host;
    xceiv_data->otg_xceiver.xceiver.shutdown =
        bcmpmu_otg_xceiv_shutdown;
    xceiv_data->otg_xceiver.xceiver.init =
        bcmpmu_otg_xceiv_start;

    xceiv_data->otg_xceiver.xceiver.set_power =
        bcmpmu_otg_xceiv_set_vbus_power;

    xceiv_data->otg_xceiver.xceiver.set_delayed_adp =
        bcmpmu_otg_xceiv_set_delayed_adp;
    xceiv_data->otg_xceiver.xceiver.set_srp_reqd =
        bcmpmu_otg_xceiv_set_srp_reqd_handler;
    xceiv_data->otg_xceiver.xceiver.pullup_on =
        bcmpmu_otg_xceiv_pullup_on;
    xceiv_data->otg_xceiver.xceiver.set_otg_enable =
        bcmpmu_otg_xceiv_set_otg_enable;
    xceiv_data->otg_xceiver.xceiver.set_suspend =
        bcmpmu_otg_xceiv_set_suspend;

    ATOMIC_INIT_NOTIFIER_HEAD(&xceiv_data->otg_xceiver.xceiver.notifier);

    xceiv_data->bcm_otg_vbus_validity_notifier.notifier_call =
        bcmpmu_otg_xceiv_vbus_notif_handler;
    bcmpmu_add_notifier(BCMPMU_USB_EVENT_VBUS_VALID,
                        &xceiv_data->bcm_otg_vbus_validity_notifier);

    xceiv_data->bcm_otg_vbus_invalidity_notifier.notifier_call =
        bcmpmu_otg_xceiv_vbus_invalid_notif_handler;
    bcmpmu_add_notifier(BCMPMU_USB_EVENT_VBUS_INVALID,
                        &xceiv_data->bcm_otg_vbus_invalidity_notifier);

    bcmpmu_add_notifier(BCMPMU_USB_EVENT_SESSION_INVALID,
                        &xceiv_data->bcm_otg_vbus_validity_notifier);

    xceiv_data->bcm_otg_id_chg_notifier.notifier_call =
        bcmpmu_otg_xceiv_id_chg_notif_handler;
    bcmpmu_add_notifier(BCMPMU_USB_EVENT_ID_CHANGE,
                        &xceiv_data->bcm_otg_id_chg_notifier);

    xceiv_data->bcm_otg_chg_detection_notifier.notifier_call =
        bcmpmu_otg_xceiv_chg_detection_notif_handler;
    bcmpmu_add_notifier(BCMPMU_USB_EVENT_USB_DETECTION,
                        &xceiv_data->bcm_otg_chg_detection_notifier);


    wake_lock_init(&xceiv_data->otg_xceiver.xceiver_wake_lock, WAKE_LOCK_SUSPEND, "otg_xcvr_wakelock");

#ifdef CONFIG_USB_OTG
    init_timer(&xceiv_data->otg_xceiver.srp_failure_timer);
    xceiv_data->otg_xceiver.srp_failure_timer.data = (unsigned long)xceiv_data;
    xceiv_data->otg_xceiver.srp_failure_timer.function = bcmpmu_otg_xceiv_srp_failure_handler;

    init_timer(&xceiv_data->otg_xceiver.sess_end_srp_timer);
    xceiv_data->otg_xceiver.sess_end_srp_timer.data = (unsigned long)xceiv_data;
    xceiv_data->otg_xceiver.sess_end_srp_timer.function = bcmpmu_otg_xceiv_sess_end_srp_timer_handler;

    error = bcm_otg_adp_init(xceiv_data);
    if (error)
        goto error_attr_host;
#endif

    otg_set_transceiver(&xceiv_data->otg_xceiver.xceiver);
    local_otg_xceiver = &xceiv_data->otg_xceiver.xceiver;

    platform_set_drvdata(pdev, xceiv_data);

    error = device_create_file(&pdev->dev, &dev_attr_host);
    if (error) {
        dev_warn(&pdev->dev, "Failed to create HOST file\n");
        goto error_attr_host;;
    }

    error = device_create_file(&pdev->dev, &dev_attr_vbus);
    if (error) {
        dev_warn(&pdev->dev, "Failed to create VBUS file\n");
        goto error_attr_vbus;
    }

    error = device_create_file(&pdev->dev, &dev_attr_wake);
    if (error) {
        dev_warn(&pdev->dev, "Failed to create WAKE file\n");
        goto error_attr_wake;
    }

    /* Save original ID value */
    bcmpmu_usb_get(xceiv_data->bcmpmu,
                   BCMPMU_USB_CTRL_GET_ID_VALUE,
                   &xceiv_data->prev_otg_id);

    /* Check if we should default to A-device */
    xceiv_data->otg_xceiver.xceiver.default_a =
        bcmpmu_otg_xceiv_check_id_gnd(xceiv_data) ||
        bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data);

    bcmpmu_otg_xceiv_set_def_state(xceiv_data,
                                   xceiv_data->otg_xceiver.xceiver.default_a);

    pm_runtime_set_active(&pdev->dev);
    pm_runtime_enable(&pdev->dev);

    dev_info(&pdev->dev, "Probing successful\n");

    return 0;

error_attr_wake:
    device_remove_file(xceiv_data->dev, &dev_attr_vbus);

error_attr_vbus:
    device_remove_file(xceiv_data->dev, &dev_attr_host);

error_attr_host:
    wake_lock_destroy(&xceiv_data->otg_xceiver.xceiver_wake_lock);
    destroy_workqueue(xceiv_data->bcm_otg_work_queue);
    bcmpmu_otg_free_regulator(xceiv_data);
    kfree(xceiv_data);
    return error;
}
int set_otg_notify(struct otg_notify *n)
{
	int ret = 0;

	if (!u_notify) {
		ret = create_usb_notify();
		if (ret) {
			pr_err("unable create_usb_notify\n");
			goto err;
		}
	}

	if (u_notify->o_notify && n) {
		pr_err("error : already set o_notify\n");
		goto err;
	}

	pr_info("registered otg_notify +\n");
	if (!n) {
		pr_err("otg notify structure is null\n");
		ret = -EFAULT;
		goto err1;
	}
	u_notify->o_notify = n;

	ATOMIC_INIT_NOTIFIER_HEAD(&u_notify->o_notify->otg_notifier);
	u_notify->otg_nb.notifier_call = otg_notifier_callback;
	ret = atomic_notifier_chain_register(&u_notify->o_notify->otg_notifier,
				&u_notify->otg_nb);
	if (ret < 0) {
		pr_err("atomic_notifier_chain_register failed\n");
		goto err1;
	}

	BLOCKING_INIT_NOTIFIER_HEAD(&u_notify->o_notify->extra_notifier);
	u_notify->extra_nb.notifier_call = extra_notifier_callback;
	ret = blocking_notifier_chain_register
		(&u_notify->o_notify->extra_notifier, &u_notify->extra_nb);
	if (ret < 0) {
		pr_err("blocking_notifier_chain_register failed\n");
		goto err2;
	}

	if (!n->unsupport_host) {
		u_notify->ndev.name = "usb_otg";
		u_notify->ndev.set_booster = n->vbus_drive;
		ret = host_notify_dev_register(&u_notify->ndev);
		if (ret < 0) {
			pr_err("host_notify_dev_register is failed\n");
			goto err3;
		}

		if (!n->vbus_drive) {
			pr_err("vbus_drive is null\n");
			goto err4;
		}
	}

	if (gpio_is_valid(n->vbus_detect_gpio) ||
			gpio_is_valid(n->redriver_en_gpio)) {
		ret = register_gpios(n);
		if (ret < 0) {
			pr_err("register_gpios is failed\n");
			goto err4;
		}
	}

	if (n->is_wakelock)
		wake_lock_init(&u_notify->wlock,
			WAKE_LOCK_SUSPEND, "usb_notify");

	if (n->booting_delay_sec) {
		INIT_DELAYED_WORK(&u_notify->b_delay.booting_work,
				  reserve_state_check);
		schedule_delayed_work(&u_notify->b_delay.booting_work,
				n->booting_delay_sec*HZ);
	}
	register_usbdev_notify();

	pr_info("registered otg_notify -\n");
	return 0;
err4:
	if (!n->unsupport_host)
		host_notify_dev_unregister(&u_notify->ndev);
err3:
	blocking_notifier_chain_unregister(&u_notify->o_notify->extra_notifier,
				&u_notify->extra_nb);
err2:
	atomic_notifier_chain_unregister(&u_notify->o_notify->otg_notifier,
				&u_notify->otg_nb);
err1:
	u_notify->o_notify = NULL;
err:
	return ret;
}
Пример #15
0
static int nop_usb_xceiv_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
	struct nop_usb_xceiv	*nop;
	enum usb_phy_type	type = USB_PHY_TYPE_USB2;
	int err;
	u32 clk_rate = 0;
	bool needs_vcc = false;
	bool needs_reset = false;

	nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
	if (!nop)
		return -ENOMEM;

	nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
							GFP_KERNEL);
	if (!nop->phy.otg)
		return -ENOMEM;

	if (dev->of_node) {
		struct device_node *node = dev->of_node;

		if (of_property_read_u32(node, "clock-frequency", &clk_rate))
			clk_rate = 0;

		needs_vcc = of_property_read_bool(node, "vcc-supply");
		needs_reset = of_property_read_bool(node, "reset-supply");

	} else if (pdata) {
		type = pdata->type;
		clk_rate = pdata->clk_rate;
		needs_vcc = pdata->needs_vcc;
		needs_reset = pdata->needs_reset;
	}

	nop->clk = devm_clk_get(&pdev->dev, "main_clk");
	if (IS_ERR(nop->clk)) {
		dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
					PTR_ERR(nop->clk));
	}

	if (!IS_ERR(nop->clk) && clk_rate) {
		err = clk_set_rate(nop->clk, clk_rate);
		if (err) {
			dev_err(&pdev->dev, "Error setting clock rate\n");
			return err;
		}
	}

	if (!IS_ERR(nop->clk)) {
		err = clk_prepare(nop->clk);
		if (err) {
			dev_err(&pdev->dev, "Error preparing clock\n");
			return err;
		}
	}

	nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
	if (IS_ERR(nop->vcc)) {
		dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
					PTR_ERR(nop->vcc));
		if (needs_vcc)
			return -EPROBE_DEFER;
	}

	nop->reset = devm_regulator_get(&pdev->dev, "reset");
	if (IS_ERR(nop->reset)) {
		dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
					PTR_ERR(nop->reset));
		if (needs_reset)
			return -EPROBE_DEFER;
	}

	nop->dev		= &pdev->dev;
	nop->phy.dev		= nop->dev;
	nop->phy.label		= "nop-xceiv";
	nop->phy.set_suspend	= nop_set_suspend;
	nop->phy.init		= nop_init;
	nop->phy.shutdown	= nop_shutdown;
	nop->phy.state		= OTG_STATE_UNDEFINED;
	nop->phy.type		= type;

	nop->phy.otg->phy		= &nop->phy;
	nop->phy.otg->set_host		= nop_set_host;
	nop->phy.otg->set_peripheral	= nop_set_peripheral;

	err = usb_add_phy_dev(&nop->phy);
	if (err) {
		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
			err);
		goto err_add;
	}

	platform_set_drvdata(pdev, nop);

	ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);

	return 0;

err_add:
	if (!IS_ERR(nop->clk))
		clk_unprepare(nop->clk);
	return err;
}
STATIC int hiusb_init_resource(struct lm_device *dev)
{
    int ret = 0;
    struct lm_device *lm_dev;
    struct hiusb_info *hiusb_info;

    lm_dev = dev;
    hiusb_info = dev->hiusb_info;

    ATOMIC_INIT_NOTIFIER_HEAD(&hiusb_info->charger_type_notifier_head);
    spin_lock_init(&hiusb_info->intr_flag_lock);
    wake_lock_init(&hiusb_info->dev_wakelock, WAKE_LOCK_SUSPEND, "hiusb_dev_wakelock");
    wake_lock_init(&hiusb_info->host_wakelock, WAKE_LOCK_SUSPEND, "hiusb_host_wakelock");
    sema_init(&hiusb_info->hiusb_info_sema, 0);
    spin_lock_init(&hiusb_info->switch_lock);
    hiusb_info->charger_type = CHARGER_REMOVED;
    hiusb_info->hiusb_status = HIUSB_OFF;
    hiusb_info->gadget_enable = 0;

    get_hw_config_int("usb/otg_without_mhl", &hiusb_info->otg_without_mhl, NULL);
    dev_info(&lm_dev->dev, "otg_without_mhl:%d.\n", hiusb_info->otg_without_mhl);

    ret = get_hw_config_int("usb/gpio_otg_int", &hiusb_info->otg_int_gpio, NULL);
    dev_info(&lm_dev->dev, "gpio_otg_int:%d.\n", hiusb_info->otg_int_gpio);

    hiusb_info->usb_block = iomux_get_block("block_switch");
    hiusb_info->usb_config = iomux_get_blockconfig("block_switch");

    hiusb_info->clk_usbotg_off= clk_get(NULL, "clk_usbotg_off");
    ret = IS_ERR(hiusb_info->clk_usbotg_off);
    if (ret) {
        dev_err(&lm_dev->dev, "get clk_usbotg_off failed!\n");
        goto get_clk_usbotg_off_fail;
    }
#if defined(CHIP_BB_HI6210)/*B020 Modify*/
#else
    hiusb_info->clk_picophy= clk_get(NULL, "clk_picophy");
    ret = IS_ERR(hiusb_info->clk_picophy);
    if (ret) {
        dev_err(&lm_dev->dev, "get clk_picophy failed!\n");
        goto get_clk_picophy_fail;
    }
#endif    
    switch_init(lm_dev);

    if (hiusb_info->vbus_pin != 0) {
        ret = gpio_request(hiusb_info->vbus_pin, "USB_VBUS");
        if (ret < 0) {
            dev_err(&dev->dev, "%s usb vbus gpio error", __func__);
            goto request_vbus_pin_fail;
        }
        gpio_direction_output(hiusb_info->vbus_pin, 0);
    }

    if (hiusb_info->phy_reset_pin != 0) {
        ret = gpio_request(hiusb_info->phy_reset_pin, "USBPHY_REST");
        if (ret < 0) {
            dev_err(&dev->dev, "%s usb phy reset gpio error", __func__);
            goto request_gpio_fail;
        }
        gpio_direction_output(hiusb_info->phy_reset_pin, 0);
        mdelay(100);
        gpio_direction_output(hiusb_info->phy_reset_pin, 1);
    }

    if (hiusb_info->otg_int_gpio != -1) {
        ret = gpio_request(hiusb_info->otg_int_gpio, "OTG_INT_GPIO");
        if (ret < 0) {
            dev_err(&dev->dev, "%s usb otg int gpio error", __func__);
            goto request_gpio_fail;
        }
        gpio_direction_input(hiusb_info->otg_int_gpio);
    }

    /* init workqueue for usb insert/draw : only for debug */
    INIT_DELAYED_WORK(&hiusb_info->otg_intr_work, hiusb_otg_intr_work);
    dev_info(&lm_dev->dev, "%s.\n", __func__);

    return 0;

request_gpio_fail:
    if (hiusb_info->vbus_pin != 0) {
        gpio_free(hiusb_info->vbus_pin);
    }
request_vbus_pin_fail:
#if defined(CHIP_BB_HI6210)/*B020 Modify*/
#else
    clk_put(hiusb_info->clk_picophy);
#endif
get_clk_picophy_fail:
    clk_put(hiusb_info->clk_usbotg_off);
get_clk_usbotg_off_fail:
    return ret;
}
int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
		enum usb_phy_type type, u32 clk_rate, bool needs_vcc)
{
	int err;

	nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
			GFP_KERNEL);
	if (!nop->phy.otg)
		return -ENOMEM;

	nop->clk = devm_clk_get(dev, "main_clk");
	if (IS_ERR(nop->clk)) {
		dev_dbg(dev, "Can't get phy clock: %ld\n",
					PTR_ERR(nop->clk));
	}

	if (!IS_ERR(nop->clk) && clk_rate) {
		err = clk_set_rate(nop->clk, clk_rate);
		if (err) {
			dev_err(dev, "Error setting clock rate\n");
			return err;
		}
	}

	nop->vcc = devm_regulator_get(dev, "vcc");
	if (IS_ERR(nop->vcc)) {
		dev_dbg(dev, "Error getting vcc regulator: %ld\n",
					PTR_ERR(nop->vcc));
		if (needs_vcc)
			return -EPROBE_DEFER;
	}

	if (gpio_is_valid(nop->gpio_reset)) {
		unsigned long gpio_flags;

		/* Assert RESET */
		if (nop->reset_active_low)
			gpio_flags = GPIOF_OUT_INIT_LOW;
		else
			gpio_flags = GPIOF_OUT_INIT_HIGH;

		err = devm_gpio_request_one(dev, nop->gpio_reset,
						gpio_flags, dev_name(dev));
		if (err) {
			dev_err(dev, "Error requesting RESET GPIO %d\n",
					nop->gpio_reset);
			return err;
		}
	}

	nop->dev		= dev;
	nop->phy.dev		= nop->dev;
	nop->phy.label		= "nop-xceiv";
	nop->phy.set_suspend	= nop_set_suspend;
	nop->phy.state		= OTG_STATE_UNDEFINED;
	nop->phy.type		= type;

	nop->phy.otg->phy		= &nop->phy;
	nop->phy.otg->set_host		= nop_set_host;
	nop->phy.otg->set_peripheral	= nop_set_peripheral;

	ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
	return 0;
}
Пример #18
0
int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
		struct usb_phy_gen_xceiv_platform_data *pdata)
{
	enum usb_phy_type type = USB_PHY_TYPE_USB2;
	int err;

	u32 clk_rate = 0;
	bool needs_vcc = false;

	nop->reset_active_low = true;	/* default behaviour */

	if (dev->of_node) {
		struct device_node *node = dev->of_node;
		enum of_gpio_flags flags = 0;

		if (of_property_read_u32(node, "clock-frequency", &clk_rate))
			clk_rate = 0;

		needs_vcc = of_property_read_bool(node, "vcc-supply");
		nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
								0, &flags);
		if (nop->gpio_reset == -EPROBE_DEFER)
			return -EPROBE_DEFER;

		nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;

	} else if (pdata) {
		type = pdata->type;
		clk_rate = pdata->clk_rate;
		needs_vcc = pdata->needs_vcc;
		nop->gpio_reset = pdata->gpio_reset;
	} else {
		nop->gpio_reset = -1;
	}

	nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
			GFP_KERNEL);
	if (!nop->phy.otg)
		return -ENOMEM;

	nop->clk = devm_clk_get(dev, "main_clk");
	if (IS_ERR(nop->clk)) {
		dev_dbg(dev, "Can't get phy clock: %ld\n",
					PTR_ERR(nop->clk));
	}

	if (!IS_ERR(nop->clk) && clk_rate) {
		err = clk_set_rate(nop->clk, clk_rate);
		if (err) {
			dev_err(dev, "Error setting clock rate\n");
			return err;
		}
	}

	nop->vcc = devm_regulator_get(dev, "vcc");
	if (IS_ERR(nop->vcc)) {
		dev_dbg(dev, "Error getting vcc regulator: %ld\n",
					PTR_ERR(nop->vcc));
		if (needs_vcc)
			return -EPROBE_DEFER;
	}

	if (gpio_is_valid(nop->gpio_reset)) {
		unsigned long gpio_flags;

		/* Assert RESET */
		if (nop->reset_active_low)
			gpio_flags = GPIOF_OUT_INIT_LOW;
		else
			gpio_flags = GPIOF_OUT_INIT_HIGH;

		err = devm_gpio_request_one(dev, nop->gpio_reset,
						gpio_flags, dev_name(dev));
		if (err) {
			dev_err(dev, "Error requesting RESET GPIO %d\n",
					nop->gpio_reset);
			return err;
		}
	}

	nop->dev		= dev;
	nop->phy.dev		= nop->dev;
	nop->phy.label		= "nop-xceiv";
	nop->phy.set_suspend	= nop_set_suspend;
	nop->phy.state		= OTG_STATE_UNDEFINED;
	nop->phy.type		= type;

	nop->phy.otg->phy		= &nop->phy;
	nop->phy.otg->set_host		= nop_set_host;
	nop->phy.otg->set_peripheral	= nop_set_peripheral;

	ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
	return 0;
}
Пример #19
0
static int __init gpio_vbus_probe(struct platform_device *pdev)
{
	struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
	struct gpio_vbus_data *gpio_vbus;
	struct resource *res;
	int err, gpio, irq;

	if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
		return -EINVAL;
	gpio = pdata->gpio_vbus;

	gpio_vbus = kzalloc(sizeof(struct gpio_vbus_data), GFP_KERNEL);
	if (!gpio_vbus)
		return -ENOMEM;

	gpio_vbus->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
	if (!gpio_vbus->phy.otg) {
		kfree(gpio_vbus);
		return -ENOMEM;
	}

	platform_set_drvdata(pdev, gpio_vbus);
	gpio_vbus->dev = &pdev->dev;
	gpio_vbus->phy.label = "gpio-vbus";
	gpio_vbus->phy.set_power = gpio_vbus_set_power;
	gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
	gpio_vbus->phy.state = OTG_STATE_UNDEFINED;

	gpio_vbus->phy.otg->phy = &gpio_vbus->phy;
	gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral;

	err = gpio_request(gpio, "vbus_detect");
	if (err) {
		dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n",
			gpio, err);
		goto err_gpio;
	}
	gpio_direction_input(gpio);

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (res) {
		irq = res->start;
		res->flags &= IRQF_TRIGGER_MASK;
		res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED;
	} else
		irq = gpio_to_irq(gpio);

	/* if data line pullup is in use, initialize it to "not pulling up" */
	gpio = pdata->gpio_pullup;
	if (gpio_is_valid(gpio)) {
		err = gpio_request(gpio, "udc_pullup");
		if (err) {
			dev_err(&pdev->dev,
				"can't request pullup gpio %d, err: %d\n",
				gpio, err);
			gpio_free(pdata->gpio_vbus);
			goto err_gpio;
		}
		gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
	}

	err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS,
		"vbus_detect", pdev);
	if (err) {
		dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
			irq, err);
		goto err_irq;
	}

	ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);

	INIT_WORK(&gpio_vbus->work, gpio_vbus_work);

	gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
	if (IS_ERR(gpio_vbus->vbus_draw)) {
		dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
			PTR_ERR(gpio_vbus->vbus_draw));
		gpio_vbus->vbus_draw = NULL;
	}

	/* only active when a gadget is registered */
	err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2);
	if (err) {
		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
			err);
		goto err_otg;
	}

	return 0;
err_otg:
	free_irq(irq, &pdev->dev);
err_irq:
	if (gpio_is_valid(pdata->gpio_pullup))
		gpio_free(pdata->gpio_pullup);
	gpio_free(pdata->gpio_vbus);
err_gpio:
	platform_set_drvdata(pdev, NULL);
	kfree(gpio_vbus->phy.otg);
	kfree(gpio_vbus);
	return err;
}