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 }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); }