static enum charge_level_t charger_detect(void)
{
	int ret;
	u8 hw_status;
	u8 vbus_status;
	
	ret = twl6030_hw_status(&hw_status);

	if (ret) {
		printf("Failed to read hw_status, reason: %d\n", ret);
		return CHARGE_DISABLE;
	}

	ret = twl6030_vbus_status(&vbus_status);	

	if (ret) {
		printf("Failed to read vbus_status, reason: %d\n", ret);
		return CHARGE_DISABLE;
	}

	printf("hw_status 0x%02x vbus_status 0x%02x\n", hw_status, vbus_status);

	if ((vbus_status & VBUS_DET) && !(hw_status & STS_USB_ID)) {
		return omap4_charger_detect();	
	} else {
		// No charger detected
		return CHARGE_DISABLE;
	}
}
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;
}
Example #3
0
static void linkstat_work(struct work_struct *work)
{
	u8 vbus_state, hw_state;
	int status = USB_EVENT_NONE;
	unsigned charger_type;
	struct archos_twl6030_usb *twl = container_of(work, struct archos_twl6030_usb, work.work);
	
	hw_state = archos_twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);	

	vbus_state = archos_twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
						CONTROLLER_STAT1);
		
//printk("hw_state: %x\n", hw_state);
//printk("vbus_state: %x\n", vbus_state);
	/* force transition to floating mode if state before is unknown */
	if (twl->state == STATE_UNKNOWN) {
printk("STATE_UNKNOWN -> STATE_NONE\n");
		twl->state = STATE_NONE;
		twl->otg.last_event = status;

		if (twl->asleep) {
			regulator_disable(twl->usb3v3);
			twl->asleep = 0;
		}

		atomic_notifier_call_chain(&twl->otg.notifier, USB_EVENT_NONE,
				twl->otg.gadget);
	}

		
/*	if (twl->state == STATE_VBUS_TRANS) {
		if (!(vbus_state & VBUS_DET)) {
			twl->state = STATE_NONE;
			archos_twl6030_phy_shutdown(&twl->otg);			
			if (twl->asleep) {
				regulator_disable(twl->usb3v3);
				twl->asleep = 0;
			}
		} else if (vbus_state & CHRG_DET_N) {
printk("STATE_VBUS_TRANS -> STATE_CHARGER\n");
			twl->state = STATE_CHARGER;
			switch_set_state(&twl->usb_switch, twl->state);
			sysfs_notify(&twl->dev->kobj, NULL, "vbus");
		} else {
		
printk("STATE_VBUS_TRANS -> STATE_VBUS\n");
			twl->otg.state = OTG_STATE_B_IDLE;
		
			twl->state = STATE_VBUS;
			twl->linkstat = USB_EVENT_VBUS;
			
			atomic_notifier_call_chain(&twl->otg.notifier,
					USB_EVENT_VBUS, twl->otg.gadget);
			switch_set_state(&twl->usb_switch, twl->state);
			sysfs_notify(&twl->dev->kobj, NULL, "vbus");
		}
	}	
*/
	if (twl->state == STATE_VBUS || twl->state == STATE_CHARGER) {
		if (!(vbus_state & VBUS_DET)) {
			enum state state = twl->state;
printk("STATE_VBUS -> STATE_NONE\n");
			twl->state = STATE_NONE;
			twl->linkstat = USB_EVENT_NONE;
			twl->otg.last_event = status;

			atomic_notifier_call_chain(&twl->otg.notifier, USB_EVENT_NONE,
					twl->otg.gadget);

			if (twl->asleep) {
				regulator_disable(twl->usb3v3);
				twl->asleep = 0;
			}
			
			switch_set_state(&twl->usb_switch, twl->state);
			sysfs_notify(&twl->dev->kobj, NULL, "vbus");

			archos_twl6030_phy_shutdown(&twl->otg);
			
		}
	} else if (twl->state == STATE_GND) {
		if (!(hw_state & STS_USB_ID)) {
printk("STATE_GND -> STATE_NONE\n");
			archos_twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
			archos_twl6030_writeb(twl, TWL_MODULE_USB,  0x1, USB_ID_INT_EN_HI_SET);

			twl->state = STATE_NONE;
			twl->otg.last_event = status;

			atomic_notifier_call_chain(&twl->otg.notifier, USB_EVENT_NONE,
					twl->otg.gadget);
			switch_set_state(&twl->usb_switch, twl->state);

			if (twl->asleep) {
				regulator_disable(twl->usb3v3);
				twl->asleep = 0;
			}
		}	
	} else { 
		if (hw_state & STS_USB_ID) {
printk("STATE_NONE -> STATE_GND\n");
			archos_twl6030_usb_ldo_init(twl);
			regulator_enable(twl->usb3v3);
			twl->asleep = 1;
			archos_twl6030_writeb(twl, TWL_MODULE_USB,  0x1, USB_ID_INT_EN_HI_CLR);
			archos_twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);

			twl->state = STATE_GND;
			twl->otg.last_event = USB_EVENT_ID;
			
			twl->otg.default_a = true;
			twl->otg.state = OTG_STATE_A_IDLE;
			atomic_notifier_call_chain(&twl->otg.notifier,
					USB_EVENT_ID, twl->otg.gadget);
		
			switch_set_state(&twl->usb_switch, twl->state);
		} else if (vbus_state & VBUS_DET) {
			archos_twl6030_usb_ldo_init(twl);
			regulator_enable(twl->usb3v3);
			//archos_twl6030_phy_init(&twl->otg);
			twl->asleep = 1;
			//twl->state = STATE_VBUS_TRANS;
			charger_type = omap4_charger_detect();
			if ((charger_type == POWER_SUPPLY_TYPE_USB_CDP) 
				|| (charger_type == POWER_SUPPLY_TYPE_USB)) {
printk("STATE_NONE -> STATE_VBUS\n");
				status = USB_EVENT_VBUS;
				twl->otg.last_event = status;
				twl->otg.default_a = false;
				twl->otg.state = OTG_STATE_B_IDLE;
				twl->linkstat = USB_EVENT_VBUS;
				twl->state = STATE_VBUS;
				twl->usb_cinlimit_mA = 500;
			} else if (charger_type == POWER_SUPPLY_TYPE_USB_DCP) {
printk("STATE_NONE -> STATE_CHARGER\n");
				status = USB_EVENT_CHARGER;
				twl->otg.last_event = status;
				twl->usb_cinlimit_mA = 1500;
				twl->state = STATE_CHARGER;
			}
			twl->prev_vbus = (vbus_state & VBUS_DET);
			switch_set_state(&twl->usb_switch, twl->state);
			atomic_notifier_call_chain(&twl->otg.notifier, status, &charger_type);
			sysfs_notify(&twl->dev->kobj, NULL, "vbus");
		}	
	}
	
	archos_twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
	twl->linkstat = status;

	if (twl->state == STATE_GND)
		schedule_delayed_work(&twl->work, HZ/10);
}
Example #4
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;
}
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;
}