Esempio n. 1
0
static void twl6030_usb_irq_wq_func(struct work_struct *twl6030_usb_irq_wq)
//static irqreturn_t twl6030_usb_irq_wq_func(int irq, void *_twl)
{
	struct twl6030_usb *twl = tmp_twl;// hunsoo _twl;
	int status  = USB_EVENT_NONE;
	int vbus_state, hw_state;


	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	vbus_state = twl6030_readb(twl, TWL6030_MODULE_CHARGER,
						CONTROLLER_STAT1);
	/* AC unplugg can also generate this IRQ
	 * we only call the notifier in case of VBUS change
	 */
	if (twl->prev_vbus != (vbus_state & VBUS_DET)) {
		if (!(hw_state & STS_USB_ID)) {
			if (vbus_state & VBUS_DET)
				status = USB_EVENT_VBUS;
			else
				status = USB_EVENT_NONE;

			if (status >= 0) {
				blocking_notifier_call_chain(&twl->otg.notifier,
						status, twl->otg.gadget);
			}
		}
		twl->linkstat = status;
		sysfs_notify(&twl->dev->kobj, NULL, "vbus");
	}
	twl->prev_vbus = vbus_state & VBUS_DET;


	return IRQ_HANDLED;
}
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{
	struct twl6030_usb *twl = _twl;
	int status;
	u8 vbus_state, hw_state;
	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)) {
		regulator_enable(twl->usb3v3);
		charger_type = omap4_charger_detect();
		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.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;
		if (twl->asleep) {

			atomic_notifier_call_chain(&twl->otg.notifier,
					status, twl->otg.gadget);
			regulator_disable(twl->usb3v3);
			twl->asleep = 0;

		}
	}
	sysfs_notify(&twl->dev->kobj, NULL, "vbus");

vbus_notify:
	twl->prev_vbus = vbus_state;
	return IRQ_HANDLED;
}
void id_monitor_work_func(struct work_struct *work)
{
    struct twl6030_usb *twl = container_of(work,
                struct twl6030_usb, vbus_work);
	int status = USB_EVENT_NONE;
	u8 hw_state;
#ifdef CONFIG_USB_MUSB_HDRC_HCD
	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	if (hw_state & STS_USB_ID) {

		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
		status = USB_EVENT_ID;
		twl->otg.default_a = true;
		twl->otg.state = OTG_STATE_A_IDLE;
		blocking_notifier_call_chain(&twl->otg.notifier, status,
							twl->otg.gadget);
	} else  {
		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
	}
	twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
	twl->linkstat = status;
#endif
    
}
Esempio n. 4
0
static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{
	struct twl6030_usb *twl = _twl;
	int status = USB_EVENT_NONE;
	u8 hw_state;

	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	if (hw_state & STS_USB_ID) {

		regulator_enable(twl->usb3v3);
		twl->asleep = 1;
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1);
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
								0x10);
		status = USB_EVENT_ID;
		twl->otg.default_a = true;
		twl->otg.state = OTG_STATE_A_IDLE;
		twl->linkstat = status;
		twl->otg.last_event = status;
		atomic_notifier_call_chain(&twl->otg.notifier, status,
							twl->otg.gadget);
	} else  {
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
								0x10);
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
								0x1);
	}
	twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status);

	return IRQ_HANDLED;
}
Esempio n. 5
0
static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
{
    char *regulator_name;
    u8 misc2_data = 0;

    if (twl->features & TWL6032_SUBCLASS)
        regulator_name = "ldousb";
    else
        regulator_name = "vusb";

    /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
    twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);

    twl->usb3v3 = regulator_get(twl->dev, regulator_name);
    if (IS_ERR(twl->usb3v3))
        return -ENODEV;

    /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
    twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);

    /*
     * Program the USB_ID_CTRL_SET register to enable GND drive
     * and the ID comparators
     */
    twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);

    /* 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);

    return 0;
}
Esempio n. 6
0
static irqreturn_t powerbutton_irq(int irq, void *_pwr)
{
	struct twl6030_pwr_button *pwr = _pwr;
	int hw_state;
	int pwr_val;
	static int prev_hw_state = 0xFFFF;
	static int push_release_flag;

	hw_state = twl6030_readb(pwr, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
	pwr_val = !(hw_state & PWR_PWRON_IRQ);
	if ((prev_hw_state != pwr_val) && (prev_hw_state != 0xFFFF)) {
		push_release_flag = 0;
		input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
		input_sync(pwr->input_dev);
	} else if (!push_release_flag) {
		push_release_flag = 1;
		input_report_key(pwr->input_dev, pwr->report_key, !pwr_val);
		input_sync(pwr->input_dev);

		msleep(20);

		input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
		input_sync(pwr->input_dev);
	} else
		push_release_flag = 0;

	prev_hw_state = pwr_val;

	return IRQ_HANDLED;
}
static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{
	struct twl6030_usb *twl = _twl;
	enum musb_vbus_id_status status = MUSB_UNKNOWN;
	u8 hw_state;
	int ret;

	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	if (hw_state & STS_USB_ID) {
		ret = regulator_enable(twl->usb3v3);
		if (ret)
			dev_err(twl->dev, "Failed to enable usb3v3\n");

		twl->asleep = 1;
		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
		status = MUSB_ID_GROUND;
		twl->linkstat = status;
		musb_mailbox(status);
	} else  {
		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
	}
	twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);

	return IRQ_HANDLED;
}
Esempio n. 8
0
static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{

#ifndef CONFIG_USB_MUSB_PERIPHERAL
	struct twl6030_usb *twl = _twl;
	int status = USB_EVENT_NONE;
	u8 hw_state, misc2_data;

	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	if (hw_state & STS_USB_ID) {

		if (twl->otg.state == OTG_STATE_A_IDLE)
			return IRQ_HANDLED;

		/* 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);
		twl->asleep = 1;
		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
		status = USB_EVENT_ID;
		twl->otg.default_a = true;
		twl->otg.state = OTG_STATE_A_IDLE;
		twl->linkstat = status;
		twl->otg.last_event = status;
		atomic_notifier_call_chain(&twl->otg.notifier, status,
							twl->otg.gadget);
	} else  {
		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
	}
	twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
#endif

	return IRQ_HANDLED;
}
Esempio n. 9
0
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{
	struct twl6030_usb *twl = _twl;
	enum musb_vbus_id_status status = MUSB_UNKNOWN;
	u8 vbus_state, hw_state;
	int ret;

	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
						CONTROLLER_STAT1);
	if (!(hw_state & STS_USB_ID)) {
		if (vbus_state & VBUS_DET) {
			ret = regulator_enable(twl->usb3v3);
			if (ret)
				dev_err(twl->dev, "Failed to enable usb3v3\n");

			twl->asleep = 1;
			status = MUSB_VBUS_VALID;
			twl->linkstat = status;
			ret = musb_mailbox(status);
			if (ret)
				twl->linkstat = MUSB_UNKNOWN;
		} else {
			if (twl->linkstat != MUSB_UNKNOWN) {
				status = MUSB_VBUS_OFF;
				twl->linkstat = status;
				ret = musb_mailbox(status);
				if (ret)
					twl->linkstat = MUSB_UNKNOWN;
				if (twl->asleep) {
					regulator_disable(twl->usb3v3);
					twl->asleep = 0;
				}
			}
		}
	}
	sysfs_notify(&twl->dev->kobj, NULL, "vbus");

	return IRQ_HANDLED;
}
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{
	struct twl6030_usb *twl = _twl;
	struct usb_otg *otg = twl->phy.otg;
	int status;
	u8 vbus_state, hw_state;

	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
						CONTROLLER_STAT1);
	if (!(hw_state & STS_USB_ID)) {
		if (vbus_state & VBUS_DET) {
			regulator_enable(twl->usb3v3);
			twl->asleep = 1;
			status = USB_EVENT_VBUS;
			otg->default_a = false;
			twl->phy.state = OTG_STATE_B_IDLE;
			twl->linkstat = status;
			twl->phy.last_event = status;
			atomic_notifier_call_chain(&twl->phy.notifier,
						status, otg->gadget);
		} else {
			status = USB_EVENT_NONE;
			twl->linkstat = status;
			twl->phy.last_event = status;
			atomic_notifier_call_chain(&twl->phy.notifier,
						status, otg->gadget);
			if (twl->asleep) {
				regulator_disable(twl->usb3v3);
				twl->asleep = 0;
			}
		}
	}
	sysfs_notify(&twl->dev->kobj, NULL, "vbus");

	return IRQ_HANDLED;
}
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{
	struct twl6030_usb *twl = _twl;
	int status;
	u8 vbus_state, hw_state;

	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
						CONTROLLER_STAT1);
	if (!(hw_state & STS_USB_ID)) {
		if (vbus_state & VBUS_DET) {
			twl6030_usb_ldo_init(twl);
			regulator_enable(twl->usb3v3);
			twl->asleep = 1;
			status = USB_EVENT_VBUS;
			twl->otg.default_a = false;
			twl->otg.state = OTG_STATE_B_IDLE;
			twl->linkstat = status;
			blocking_notifier_call_chain(&twl->otg.notifier,
						status, twl->otg.gadget);
		} else {
			status = USB_EVENT_NONE;
			twl->linkstat = status;
			blocking_notifier_call_chain(&twl->otg.notifier,
						status, twl->otg.gadget);
			if (twl->asleep) {
				regulator_disable(twl->usb3v3);
				twl->asleep = 0;
			}
			wake_lock_timeout(&twl_lock,1*HZ);
		}
	}
	sysfs_notify(&twl->dev->kobj, NULL, "vbus");

	return IRQ_HANDLED;
}
static int twl6030_usb_resume(struct platform_device *pdev){
    struct twl6030_usb *twl = platform_get_drvdata(pdev);
    //printk("%s \n",__func__);
    int vbus_state = twl6030_readb(twl, TWL6030_MODULE_CHARGER,
						CONTROLLER_STAT1);
    /* AC unplugg can also generate this IRQ
     * we only call the notifier in case of VBUS change
     */
    if (twl->prev_vbus != (vbus_state & VBUS_DET)) {	 
                wake_lock(&twlusb_lock);
		queue_work(vbusid_work_queue, &twl->vbus_work);
    }
    /* Program MISC2 register and set bit VUSB_IN_VBAT */
    twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, MISC2);
    return 0;
}
Esempio n. 13
0
static void twl6030_usbotg_irq_wq_func(struct work_struct *twl6030_usbotg_irq_wq)
//static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{
	struct twl6030_usb *twl = tmp_twl_otg; // _twl;
	int status ;

	status = twl6030_readb(twl, TWL_MODULE_USB, USB_ID_INT_SRC);

	if (status & ID_GND) {
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR,
								status);

		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1);
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
								0x10);
		status = USB_EVENT_ID;

		blocking_notifier_call_chain(&twl->otg.notifier, status,
							twl->otg.gadget);

		twl->otg.default_a = true;
		twl->otg.state = OTG_STATE_A_IDLE;

	} else if (status & ID_FLOAT) {

		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR,
								status);
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
								0x10);
		twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
								0x1);

		twl->otg.default_a = false;
		twl->otg.state = OTG_STATE_B_IDLE;
		blocking_notifier_call_chain(&twl->otg.notifier, status,
					twl->otg.gadget);
	}
	twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status);

	sysfs_notify(&twl->dev->kobj, NULL, "vbus");

	return IRQ_HANDLED;
}
static int twl6030_phy_init(struct otg_transceiver *x)
{
	u8 hw_state;
	struct twl6030_usb *twl;
	struct device *dev;
	struct twl4030_usb_data *pdata;

	twl = xceiv_to_twl(x);
	dev  = twl->dev;
	pdata = dev->platform_data;

	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

	if (hw_state & STS_USB_ID)
		pdata->phy_power(twl->dev, 1, 1);
	else
		pdata->phy_power(twl->dev, 0, 1);

	return 0;
}
Esempio n. 15
0
static int twl6030_set_hz_mode(struct otg_transceiver *x, bool enabled)
{
    u8 val;
    struct twl6030_usb *twl;

    if (!x)
        return -ENODEV;

    twl = xceiv_to_twl(x);

    /* set/reset USB charger in High impedence mode on VBUS */
    val = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
                        CHARGERUSB_CTRL1);

    if (enabled)
        val |= HZ_MODE;
    else
        val &= ~HZ_MODE;

    twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , val,
                   CHARGERUSB_CTRL1);

    return 0;
}
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;
	if((vbus_state) && (!is_mhl_initialized())){
		hw_state = 0;
	}

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

	wake_lock(&twl_lock);

	if ((vbus_state) && !(hw_state & STS_USB_ID)) {
		msleep(500);		

		/* 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;
            plugin_stat = PLUGIN_USB_CHARGER;
			dev_info(twl->dev, " %s USB_EVENT_VBUS\n",__func__);
		} 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;
            plugin_stat = PLUGIN_AC_CHARGER;
			dev_info(twl->dev, " %s USB_EVENT_CHARGER\n",__func__);
		} 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;
        plugin_stat = PLUGIN_DEVICE_NONE;
		dev_info(twl->dev, " %s USB_EVENT_NONE\n",__func__);
		atomic_notifier_call_chain(&twl->otg.notifier,
				status, twl->otg.gadget);
		if (twl->asleep) {
			printk("<Du Wei> Turn off USB LDO\n");
			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;

	wake_unlock(&twl_lock);

	return IRQ_HANDLED;
}
Esempio n. 17
0
static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{

#ifndef CONFIG_USB_MUSB_PERIPHERAL
    struct twl6030_usb *twl = _twl;
    int status = USB_EVENT_NONE;
    u8 hw_state, misc2_data;

    hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);

    if (hw_state & STS_USB_ID) {
        if (twl->otg.state != OTG_STATE_A_IDLE) {
            /* 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);
            twl->asleep = 1;
            twl6030_writeb(twl, TWL_MODULE_USB, 0x1,
                           USB_ID_INT_EN_HI_CLR);
            twl6030_writeb(twl, TWL_MODULE_USB, 0x10,
                           USB_ID_INT_EN_HI_SET);

            status = USB_EVENT_ID;
            twl->otg.default_a = true;
            twl->otg.state = OTG_STATE_A_IDLE;
            twl->linkstat = status;
            twl->otg.last_event = status;
            atomic_notifier_call_chain(&twl->otg.notifier, status,
                                       twl->otg.gadget);
            /*
             * NOTE:
             * This is workaround for the TWL6032 thats missed VBUS
             * detection interrupts while OPA_MODE is set to 1 in
             * the CHARGERUSB_CTRL1.
             * Just set prev_vbus to VBUS_DET and do sysfs_notify.
             */
            if (twl->features & TWL6032_SUBCLASS) {
                sysfs_notify(&twl->dev->kobj, NULL, "vbus");
                twl->prev_vbus = VBUS_DET;
            }
        }
    } else  {
        /*
         * NOTE:
         * This is workaround for the TWL6032 thats missed VBUS
         * detection interrupts while OPA_MODE is set to 1 in
         * the CHARGERUSB_CTRL1. Just set BOOST mode for OTG to off
         * and VBUS interrupts will start to work.
         */
        if (twl->features & TWL6032_SUBCLASS) {
            twl->vbus_enable = 0;
            twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
                           CHARGERUSB_CTRL1);
        }

        twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
        twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
    }
    /* clear interrupt flags*/
    twl6030_writeb(twl, TWL_MODULE_USB, 0x1F, USB_ID_INT_LATCH_CLR);
#endif

    return IRQ_HANDLED;
}
Esempio n. 18
0
static void twl6030_usb_irq_work(struct work_struct *work)
{
    struct twl6030_usb *twl = container_of(work, struct twl6030_usb, usb_irq_work);
    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;

    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;
}
void vbus_monitor_work_func(struct work_struct *work)
{
    struct twl6030_usb *twl = container_of(work,
                struct twl6030_usb, vbus_work);
    int event  = -1;    unsigned long flags;
    int vbus_state, hw_state;
    int detect_result=0;u32 value=0;
    //spin_lock_irqsave(&twl->lock, flags);
#ifdef CONFIG_USB_MUSB_HDRC_HCD
    hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
#endif 
    vbus_state = twl6030_readb(twl, TWL6030_MODULE_CHARGER,
						CONTROLLER_STAT1);
    /* AC unplugg can also generate this IRQ
     * we only call the notifier in case of VBUS change
     */
    if (twl->prev_vbus != (vbus_state & VBUS_DET)) {
        //printk("\n%s twl->prev_vbus=%d vbus_state=%d \n",__func__,twl->prev_vbus,vbus_state & VBUS_DET);
        twl->prev_vbus = vbus_state & VBUS_DET;
#ifdef CONFIG_USB_MUSB_HDRC_HCD    
        if (!(hw_state & STS_USB_ID)) {
#endif        
            if (vbus_state & VBUS_DET) {
                wake_lock(&twlusb_lock);
                regulator_enable(twl->vusb);
                if(twl->mbid==0){//detect by omap
                    //printk("%s DETECT_BY_PHY\n",__func__);
                    
                    blocking_notifier_call_chain(&twl->otg.notifier,USB_EVENT_DETECT_SOURCE, twl->otg.gadget);
                    detect_result=detect_usb();
                    if(detect_result==PHY_DETECT_PC)
                        event = USB_EVENT_VBUS;
                    else if(detect_result==PHY_DETECT_DEDICATED_CHARGER)
                        event = USB_EVENT_CHARGER;
                    else if(detect_result==PHY_DETECT_HOST_CHARGER)
                        event = USB_EVENT_HOST_CHARGER;
                    else 
                        event = USB_EVENT_CHARGER;
                    twl->otg.default_a = false;
                    twl->otg.state = OTG_STATE_B_IDLE;
                }else{//detect by charger
                    //printk("%s DETECT_BY_CHARGER\n",__func__);
                    __raw_writel(0x40000000,OMAP2_L4_IO_ADDRESS(0x4a100000 + (0x620)));
                    event = USB_EVENT_DETECT_SOURCE;
                    twl->otg.default_a = false;
                    twl->otg.state = OTG_STATE_B_IDLE;
                }
            }else{
                //printk("!!%s USB_EVENT_NONE\n\n",__func__);
                event = USB_EVENT_NONE;
                //regulator_disable(twl->vusb);
            }
            if (event >= 0) {
                twl->linkstat = event;
                blocking_notifier_call_chain(&twl->otg.notifier,event, twl->otg.gadget);
            }
#ifdef CONFIG_USB_MUSB_HDRC_HCD            
        }
#endif        
        sysfs_notify(&twl->dev->kobj, NULL, "vbus");
    }
    if(event == USB_EVENT_NONE) {
        wake_unlock(&twlusb_lock);
    }
}
static int __devinit twl6030_usb_probe(struct platform_device *pdev)
{
	struct twl6030_usb	*twl;
	int			status,err,vbus_state;
	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	= twl6030_set_host;
	twl->otg.set_peripheral	= twl6030_set_peripheral;
	twl->otg.set_suspend	= twl6030_set_suspend;
	twl->asleep		= 1;
	#ifndef CONFIG_USB_ETH_RNDIS
	twl->otg.set_power	= twl6030_set_input_current_limit;
	twl->otg.set_vbus	= twl6030_set_vbus;
	#endif
	twl->otg.set_hz_mode	= twl6030_set_hz_mode;
	twl->otg.init		= phy_init;
	twl->otg.shutdown	= phy_shutdown;
	twl->otg.enable_irq	= twl6030_enable_irq;
	twl->otg.set_clk	= set_phy_clk;
	twl->otg.shutdown	= phy_shutdown;
	twl->prev_vbus		= 0;
	twl->vusb = regulator_get(NULL, "usb-phy");
        if (IS_ERR(twl->vusb)) {
            pr_err("Unable to get usb-phy regulator\n");
        }
        
        twl->mbid=quanta_get_mbid();
        printk(KERN_INFO "%s mbid=%d\n",__func__,twl->mbid);
        err = regulator_set_voltage(twl->vusb, 3300000,
                    3300000);
        //regulator_disable(twl->vusb);

	/* 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");

	BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
        INIT_WORK(&twl->vbus_work, vbus_monitor_work_func);
        INIT_WORK(&twl->id_work, id_monitor_work_func);
	/* 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 = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"twl6030_usb", twl);
	if (status < 0) {
		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq1, status);
		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_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
			twl->irq2, status);
		kfree(twl);
		return status;
	}

        vbus_state = twl6030_readb(twl, TWL6030_MODULE_CHARGER,
						CONTROLLER_STAT1);
        wake_lock_init(&twlusb_lock, WAKE_LOCK_SUSPEND, "usb_wake_lock");

	ctrl_base = ioremap(0x4A002000, SZ_1K);
	/* power down the phy by default can be enabled on connect */
	__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);

	dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
	return 0;
}
static irqreturn_t powerbutton_irq(int irq, void *_pwr)
{
	struct twl6030_pwr_button *pwr = _pwr;
	int hw_state;
	int pwr_val;
	static int prev_hw_state = 0xFFFF;
	static int push_release_flag;

	hw_state = twl6030_readb(pwr, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
	pwr_val = !(hw_state & PWR_PWRON_IRQ);
    printk("%s: power button status %d\n", __func__, pwr_val);
//[email protected] => [START]  keylock command
#if defined(CONFIG_MACH_LGE_COSMO) || defined(CONFIG_MACH_LGE_CX2)
	if ((prev_hw_state != pwr_val) && (prev_hw_state != 0xFFFF) && (!atcmd_keylock)) {
#else
	if ((prev_hw_state != pwr_val) && (prev_hw_state != 0xFFFF)) {
#endif
//[email protected] <= [END]
		push_release_flag = 0;
		input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
		input_sync(pwr->input_dev);
//[email protected] => [START]  keylock command
#if defined(CONFIG_MACH_LGE_COSMO) || defined(CONFIG_MACH_LGE_CX2)
	} else if ((!push_release_flag) && (!atcmd_keylock)) {
#else
	} else if (!push_release_flag) {
#endif
//[email protected] <= [END]
		push_release_flag = 1;
		input_report_key(pwr->input_dev, pwr->report_key, !pwr_val);
		input_sync(pwr->input_dev);

		msleep(20);

		input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
		input_sync(pwr->input_dev);
	} else
		push_release_flag = 0;

	prev_hw_state = pwr_val;

	return IRQ_HANDLED;
}

static int __devinit twl6030_pwrbutton_probe(struct platform_device *pdev)
{
	struct twl6030_pwr_button *pwr_button;
	int irq = platform_get_irq(pdev, 0);
	int err = -ENODEV;

	pr_info("%s: Enter\n", __func__);
	pwr_button = kzalloc(sizeof(struct twl6030_pwr_button), GFP_KERNEL);
	if (!pwr_button)
		return -ENOMEM;

	pwr_button->input_dev = input_allocate_device();
	if (!pwr_button->input_dev) {
		dev_dbg(&pdev->dev, "Can't allocate power button\n");
		goto input_error;
	}

	__set_bit(EV_KEY, pwr_button->input_dev->evbit);

	pwr_button->report_key = KEY_POWER;
	pwr_button->dev = &pdev->dev;
	pwr_button->input_dev->evbit[0] = BIT_MASK(EV_KEY);
	pwr_button->input_dev->keybit[BIT_WORD(pwr_button->report_key)] =
			BIT_MASK(pwr_button->report_key);
	pwr_button->input_dev->name = "twl6030_pwrbutton";
	pwr_button->input_dev->phys = "twl6030_pwrbutton/input0";
	pwr_button->input_dev->dev.parent = &pdev->dev;

	err = request_threaded_irq(irq, NULL, powerbutton_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"twl6030_pwrbutton", pwr_button);
	if (err < 0) {
		dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
		goto free_input_dev;
	}

	err = input_register_device(pwr_button->input_dev);
	if (err) {
		dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
		goto free_irq;
	}

	twl6030_interrupt_unmask(0x01, REG_INT_MSK_LINE_A);
	twl6030_interrupt_unmask(0x01, REG_INT_MSK_STS_A);

	platform_set_drvdata(pdev, pwr_button);

	return 0;

free_irq:
	free_irq(irq, NULL);
free_input_dev:
	input_free_device(pwr_button->input_dev);
input_error:
	kfree(pwr_button);
	return err;
}

static int __devexit twl6030_pwrbutton_remove(struct platform_device *pdev)
{
	struct input_dev *pwr = platform_get_drvdata(pdev);
	int irq = platform_get_irq(pdev, 0);

	free_irq(irq, pwr);
	input_unregister_device(pwr);

	return 0;
}

struct platform_driver twl6030_pwrbutton_driver = {
	.probe		= twl6030_pwrbutton_probe,
	.remove		= __devexit_p(twl6030_pwrbutton_remove),
	.driver		= {
		.name	= "twl6030_pwrbutton",
		.owner	= THIS_MODULE,
	},
};

static int __init twl6030_pwrbutton_init(void)
{
	return platform_driver_register(&twl6030_pwrbutton_driver);
}
module_init(twl6030_pwrbutton_init);

static void __exit twl6030_pwrbutton_exit(void)
{
	platform_driver_unregister(&twl6030_pwrbutton_driver);
}