static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { char *regulator_name; if (twl->features & TWL6025_SUBCLASS) regulator_name = "ldousb"; else regulator_name = "vusb"; twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG); twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2); twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2); twl->usb3v3 = regulator_get(twl->dev, regulator_name); if (IS_ERR(twl->usb3v3)) return -ENODEV; twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET); twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET); return 0; }
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; }
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 int twl6030_usb_ldo_init(struct twl6030_usb *twl) { char *regulator_name; if (twl->features & TWL6025_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); /* Program CFG_LDO_PD2 register and set VUSB bit */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2); /* Program MISC2 register and set bit VUSB_IN_VBAT */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2); 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); return 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; }
static int twl6030_start_srp(struct phy_companion *comparator) { struct twl6030_usb *twl = comparator_to_twl(comparator); twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET); twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET); mdelay(100); twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR); return 0; }
static int twl6030_start_srp(struct usb_otg *otg) { struct twl6030_usb *twl = phy_to_twl(otg->phy); twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET); twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET); mdelay(100); twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR); return 0; }
static int twl6030_start_srp(struct otg_transceiver *x) { struct twl6030_usb *twl = xceiv_to_twl(x); twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET); twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET); mdelay(100); twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR); return 0; }
static void otg_set_vbus_work(struct work_struct *data) { struct twl6030_usb *twl = container_of(data, struct twl6030_usb, set_vbus_work); if (twl->vbus_enable) twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40, CHARGERUSB_CTRL1); else twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00, CHARGERUSB_CTRL1); }
static void otg_set_vbus_work(struct work_struct *data) { struct twl6030_usb *twl = container_of(data, struct twl6030_usb, set_vbus_work); /* * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1 * register. This enables boost mode. */ if (twl->vbus_enable) twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40, CHARGERUSB_CTRL1); else twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00, CHARGERUSB_CTRL1); }
static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled) { struct twl6030_usb *twl = xceiv_to_twl(x); /* * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1 * register. This enables boost mode. */ if (enabled) twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40, CHARGERUSB_CTRL1); else twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00, CHARGERUSB_CTRL1); return 0; }
static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { #ifdef CONFIG_USB_MUSB_HDRC_HCD /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP*/ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, USB_BACKUP_REG); # else /* Turn off the ID_WAKEUP_COMP*/ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x0, USB_BACKUP_REG); #endif /* Set Pull-down is enabled when VUSB and VUSIM is in OFF state */ //twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x3, CFG_LDO_PD2); /* Program MISC2 register and set bit VUSB_IN_VBAT */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, MISC2); /* * Program the VUSB_CFG_VOLTAGE register to set the VUSB * voltage to 3.3V */ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x0, VUSB_CFG_GRP); /* Program the VUSB_CFG_TRANS for ACTIVE state. */ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x0, VUSB_CFG_TRANS); /* Program the VUSB_CFG_TRANS for ACTIVE state. */ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x0, VUSB_CFG_TRANS); /* Program the VUSB_CFG_STATE register to ON on all groups. */ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x0, VUSB_CFG_STATE); #if 1 u8 data2; twl_i2c_read_u8(TWL6030_MODULE_ID0, &data2, 0xE6); printk("!!!!!BBSPOR_CFG = %2x\n",data2); twl_i2c_write_u8(TWL6030_MODULE_ID0, data2 | 0x20, 0xE6); printk("!!!!!BBSPOR_CFG = %2x\n",data2 | 0x20); #endif /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */ twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET); #ifdef CONFIG_USB_MUSB_HDRC_HCD /* * Program the USB_ID_CTRL_SET register to enable GND drive * and the ID comparators */ twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_ID_CTRL_SET); #endif return 0; }
static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG); /* Program CFG_LDO_PD2 register and set VUSB bit */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2); /* Program MISC2 register and set bit VUSB_IN_VBAT */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2); if (!twl->usb3v3) { twl->usb3v3 = regulator_get(twl->dev, "vusb"); 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); /* CHARGERUSB_CTRL3 */ twl6030_writeb(twl, TWL6030_MODULE_ID1, 0x01, 0xEA); return 0; }
static int twl6030_enable_irq(struct twl6030_usb *twl) { twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); return 0; }
static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { char *regulator_name; u8 misc2_data = 0; u8 rd_reg = 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; rd_reg = twl6030_readb(twl, TWL_MODULE_USB, USB_VBUS_CTRL_SET); rd_reg = rd_reg | VBUS_ACT_COMP |VBUS_MEAS; /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */ twl6030_writeb(twl, TWL_MODULE_USB, rd_reg, USB_VBUS_CTRL_SET); /* * Program the USB_ID_CTRL_SET register to enable GND drive * and the ID comparators */ rd_reg = twl6030_readb(twl, TWL_MODULE_USB, USB_ID_CTRL_SET); rd_reg = rd_reg | ID_SRC_16U | ID_ACT_COMP |ID_MEAS; twl6030_writeb(twl, TWL_MODULE_USB, rd_reg, 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 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 int twl6030_enable_irq(struct otg_transceiver *x) { struct twl6030_usb *twl = xceiv_to_twl(x); twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, 0x1); twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); twl6030_usb_irq(twl->irq2, twl); twl6030_usbotg_irq(twl->irq1, twl); return 0; }
static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP*/ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, USB_BACKUP_REG); /* Program CFG_LDO_PD2 register and set VUSB bit */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, CFG_LDO_PD2); /* Program MISC2 register and set bit VUSB_IN_VBAT */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, MISC2); /* * Program the VUSB_CFG_VOLTAGE register to set the VUSB * voltage to 3.3V */ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x18, VUSB_CFG_VOLTAGE); /* Program the VUSB_CFG_TRANS for ACTIVE state. */ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x3F, VUSB_CFG_TRANS); /* Program the VUSB_CFG_STATE register to ON on all groups. */ twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0xE1, VUSB_CFG_STATE); /* 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, 0x4, USB_ID_CTRL_SET); 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_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_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 int __devinit twl6030_usb_probe(struct platform_device *pdev) { struct twl6030_usb *twl; int status; 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_vbus = twl6030_set_vbus; twl->otg.set_hz_mode = twl6030_set_hz_mode; twl->otg.init = twl6030_phy_init; twl->otg.shutdown = twl6030_phy_shutdown; twl->otg.enable_irq = twl6030_enable_irq; /*We need to make sure ID comparator is ON*/ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG); /* init spinlock for workqueue */ spin_lock_init(&twl->lock); wake_lock_init(&twl_lock, WAKE_LOCK_SUSPEND, "twl_wake_lock"); 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); 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_enable_irq(&twl->otg); dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); return 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; }
/* 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; }