Esempio n. 1
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;
}
Esempio n. 2
0
    /* clear interrupt flags*/
    twl6030_writeb(twl, TWL_MODULE_USB, 0x1F, USB_ID_INT_LATCH_CLR);
#endif
}

static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{
#ifndef CONFIG_USB_MUSB_PERIPHERAL
    struct twl6030_usb *twl = (struct twl6030_usb*)_twl;

    if(!twl)
        return IRQ_HANDLED;

    schedule_work(&twl->usbotg_irq_work);
#endif
    return IRQ_HANDLED;
}

#else /*                 */
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{
    struct twl6030_usb *twl = _twl;
    int status;
    u8 vbus_state, hw_state, misc2_data;
    unsigned charger_type;

    hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

    vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
                               CONTROLLER_STAT1);
    vbus_state = vbus_state & VBUS_DET;

    /* Ignore charger events other than VBUS */
    if (vbus_state == twl->prev_vbus)
        return IRQ_HANDLED;

    if ((vbus_state) && !(hw_state & STS_USB_ID)) {
        /* Program MISC2 register and set bit VUSB_IN_VBAT */
        misc2_data = twl6030_readb(twl, TWL6030_MODULE_ID0,
                                   TWL6030_MISC2);
        misc2_data |= 0x10;
        twl6030_writeb(twl, TWL6030_MODULE_ID0, misc2_data,
                       TWL6030_MISC2);

        regulator_enable(twl->usb3v3);
        twl6030_phy_suspend(&twl->otg, 0);
        charger_type = omap4_charger_detect();
        twl6030_phy_suspend(&twl->otg, 1);
        if ((charger_type == POWER_SUPPLY_TYPE_USB_CDP)
                || (charger_type == POWER_SUPPLY_TYPE_USB)) {

            status = USB_EVENT_VBUS;
            twl->otg.default_a = false;
            twl->asleep = 1;
            twl->otg.state = OTG_STATE_B_IDLE;
            twl->linkstat = status;
            twl->otg.last_event = status;
        } else if (charger_type == POWER_SUPPLY_TYPE_USB_DCP) {
            regulator_disable(twl->usb3v3);
            status = USB_EVENT_CHARGER;
            twl->usb_cinlimit_mA = 1800;
            twl->otg.state = OTG_STATE_B_IDLE;
            twl->linkstat = status;
            twl->otg.last_event = status;
        } else {
            regulator_disable(twl->usb3v3);
            goto vbus_notify;
        }
        atomic_notifier_call_chain(&twl->otg.notifier,
                                   status, &charger_type);
    }
    if (!vbus_state) {
        status = USB_EVENT_NONE;
        twl->linkstat = status;
        twl->otg.last_event = status;
        atomic_notifier_call_chain(&twl->otg.notifier,
                                   status, twl->otg.gadget);
        if (twl->asleep) {
            regulator_disable(twl->usb3v3);
            twl->asleep = 0;
            /* Program MISC2 register and clear bit VUSB_IN_VBAT */
            misc2_data = twl6030_readb(twl, TWL6030_MODULE_ID0,
                                       TWL6030_MISC2);
            misc2_data &= 0xEF;
            twl6030_writeb(twl, TWL6030_MODULE_ID0, misc2_data,
                           TWL6030_MISC2);
        }
    }

vbus_notify:
    sysfs_notify(&twl->dev->kobj, NULL, "vbus");
    twl->prev_vbus = vbus_state;
    return IRQ_HANDLED;
}