static void tahvo_usb_vbus_interrupt(unsigned long arg) { struct tahvo_usb *tu = (struct tahvo_usb *) arg; tahvo_ack_irq(TAHVO_INT_VBUSON); /* Seems we need this to acknowledge the interrupt */ tahvo_read_reg(TAHVO_REG_IDSR); schedule_work(&tu->irq_work); }
static void check_vbus_state(struct tahvo_usb *tu) { int reg, prev_state; reg = tahvo_read_reg(TAHVO_REG_IDSR); if (reg & 0x01) { u32 l; vbus_active = 1; switch (tu->otg.state) { case OTG_STATE_B_IDLE: /* Enable the gadget driver */ if (tu->otg.gadget) usb_gadget_vbus_connect(tu->otg.gadget); /* Set B-session valid and not B-sessio ended to indicate * Vbus to be ok. */ l = omap_readl(OTG_CTRL); l &= ~OTG_BSESSEND; l |= OTG_BSESSVLD; omap_writel(l, OTG_CTRL); tu->otg.state = OTG_STATE_B_PERIPHERAL; break; case OTG_STATE_A_IDLE: /* Session is now valid assuming the USB hub is driving Vbus */ tu->otg.state = OTG_STATE_A_HOST; host_resume(tu); break; default: break; } printk("USB cable connected\n"); } else { switch (tu->otg.state) { case OTG_STATE_B_PERIPHERAL: if (tu->otg.gadget) usb_gadget_vbus_disconnect(tu->otg.gadget); tu->otg.state = OTG_STATE_B_IDLE; break; case OTG_STATE_A_HOST: tu->otg.state = OTG_STATE_A_IDLE; break; default: break; } printk("USB cable disconnected\n"); vbus_active = 0; } prev_state = tu->vbus_state; tu->vbus_state = reg & 0x01; if (prev_state != tu->vbus_state) sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); }
static int tahvo_usb_set_suspend(struct otg_transceiver *dev, int suspend) { struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg); u16 w; dev_dbg(&tu->pt_dev->dev, "set_suspend\n"); w = tahvo_read_reg(TAHVO_REG_USBR); if (suspend) w &= ~USBR_NSUSPEND; else w |= USBR_NSUSPEND; tahvo_write_reg(TAHVO_REG_USBR, w); return 0; }
static int tahvo_usb_probe(struct device *dev) { struct tahvo_usb *tu; int ret; dev_dbg(dev, "probe\n"); /* Create driver data */ tu = kmalloc(sizeof(*tu), GFP_KERNEL); if (!tu) return -ENOMEM; memset(tu, 0, sizeof(*tu)); tu->pt_dev = container_of(dev, struct platform_device, dev); #ifdef CONFIG_USB_OTG /* Default mode */ #ifdef CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT tu->tahvo_mode = TAHVO_MODE_HOST; #else tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; #endif #endif INIT_WORK(&tu->irq_work, tahvo_usb_irq_work); mutex_init(&tu->serialize); /* Set initial state, so that we generate kevents only on * state changes */ tu->vbus_state = tahvo_read_reg(TAHVO_REG_IDSR) & 0x01; /* We cannot enable interrupt until omap_udc is initialized */ ret = tahvo_request_irq(TAHVO_INT_VBUSON, tahvo_usb_vbus_interrupt, (unsigned long) tu, "vbus_interrupt"); if (ret != 0) { kfree(tu); printk(KERN_ERR "Could not register Tahvo interrupt for VBUS\n"); return ret; } /* Attributes */ ret = device_create_file(dev, &dev_attr_vbus_state); #ifdef CONFIG_USB_OTG ret |= device_create_file(dev, &dev_attr_otg_mode); #endif if (ret) printk(KERN_ERR "attribute creation failed: %d\n", ret); /* Create OTG interface */ tahvo_usb_power_off(tu); tu->otg.state = OTG_STATE_UNDEFINED; tu->otg.label = DRIVER_NAME; tu->otg.set_host = tahvo_usb_set_host; tu->otg.set_peripheral = tahvo_usb_set_peripheral; tu->otg.set_power = tahvo_usb_set_power; tu->otg.set_suspend = tahvo_usb_set_suspend; tu->otg.start_srp = tahvo_usb_start_srp; tu->otg.start_hnp = tahvo_usb_start_hnp; ret = otg_set_transceiver(&tu->otg); if (ret < 0) { printk(KERN_ERR "Cannot register USB transceiver\n"); kfree(tu); tahvo_free_irq(TAHVO_INT_VBUSON); return ret; } dev->driver_data = tu; /* Act upon current vbus state once at startup. A vbus state irq may or * may not be generated in addition to this. */ schedule_work(&tu->irq_work); return 0; }
static int __init tahvo_usb_probe(struct platform_device *pdev) { struct tahvo_usb *tu; struct device *dev = &pdev->dev; int ret; int irq; dev_dbg(dev, "probe\n"); /* Create driver data */ tu = kzalloc(sizeof(*tu), GFP_KERNEL); if (!tu) return -ENOMEM; tahvo_usb_device = tu; tu->dev = dev; tu->pt_dev = pdev; #ifdef CONFIG_USB_OTG /* Default mode */ #ifdef CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT tu->tahvo_mode = TAHVO_MODE_HOST; #else tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; #endif #endif mutex_init(&tu->serialize); tu->ick = clk_get(NULL, "usb_l4_ick"); if (IS_ERR(tu->ick)) { dev_err(dev, "Failed to get usb_l4_ick\n"); ret = PTR_ERR(tu->ick); goto err_free_tu; } clk_enable(tu->ick); /* Set initial state, so that we generate kevents only on * state changes */ tu->vbus_state = tahvo_read_reg(tu->dev, TAHVO_REG_IDSR) & 0x01; irq = platform_get_irq(pdev, 0); tu->irq = irq; /* We cannot enable interrupt until omap_udc is initialized */ ret = request_threaded_irq(irq, NULL, tahvo_usb_vbus_interrupt, IRQF_ONESHOT, "tahvo-vbus", tu); if (ret != 0) { printk(KERN_ERR "Could not register Tahvo interrupt for VBUS\n"); goto err_release_clk; } /* Attributes */ ret = device_create_file(dev, &dev_attr_vbus_state); #ifdef CONFIG_USB_OTG ret |= device_create_file(dev, &dev_attr_otg_mode); #endif if (ret) printk(KERN_ERR "attribute creation failed: %d\n", ret); /* Create OTG interface */ tahvo_usb_power_off(tu); tu->otg.state = OTG_STATE_UNDEFINED; tu->otg.label = DRIVER_NAME; tu->otg.set_host = tahvo_usb_set_host; tu->otg.set_peripheral = tahvo_usb_set_peripheral; tu->otg.set_power = tahvo_usb_set_power; tu->otg.set_suspend = tahvo_usb_set_suspend; tu->otg.start_srp = tahvo_usb_start_srp; tu->otg.start_hnp = tahvo_usb_start_hnp; ret = otg_set_transceiver(&tu->otg); if (ret < 0) { printk(KERN_ERR "Cannot register USB transceiver\n"); goto err_free_irq; } dev_set_drvdata(dev, tu); return 0; err_free_irq: free_irq(tu->irq, tu); err_release_clk: clk_disable(tu->ick); clk_put(tu->ick); err_free_tu: kfree(tu); tahvo_usb_device = NULL; return ret; }