static void palmas_enable_irq(struct palmas_usb *palmas_usb) { int ret; palmas_usb->vbus_linkstat = PALMAS_USB_STATE_INIT; palmas_usb->id_linkstat = PALMAS_USB_STATE_INIT; palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_VBUS_CTRL_SET, PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP); palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_CTRL_CLEAR, PALMAS_USB_ID_CTRL_SET_ID_SRC_5U); palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_CTRL_SET, PALMAS_USB_ID_CTRL_SET_ID_SRC_16U | PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP); if (palmas_usb->enable_vbus_detection) palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb); if (palmas_usb->enable_id_detection) { /* Wait for the comparator to update status */ msleep(palmas_usb->cable_debounce_time); ret = palmas_usb_id_state_update(palmas_usb); if (ret == -EAGAIN) schedule_delayed_work(&palmas_usb->cable_update_wq, msecs_to_jiffies(palmas_usb->cable_debounce_time)); } }
static void palmas_enable_irq(struct palmas_usb *palmas_usb) { palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_VBUS_CTRL_SET, PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP); if (palmas_usb->enable_id_detection) { palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_CTRL_SET, PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP); palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_INT_EN_HI_SET, PALMAS_USB_ID_INT_EN_HI_SET_ID_GND | PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT); } if (palmas_usb->enable_vbus_detection) palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb); /* cold plug for host mode needs this delay */ if (palmas_usb->enable_id_detection) { msleep(30); palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb); } }
static int palmas_usb_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct palmas_usb *palmas_usb; int status; palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL); if (!palmas_usb) return -ENOMEM; if (node && !pdata) { palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup"); palmas_usb->enable_id_detection = of_property_read_bool(node, "ti,enable-id-detection"); palmas_usb->enable_vbus_detection = of_property_read_bool(node, "ti,enable-vbus-detection"); } else { palmas_usb->wakeup = true; palmas_usb->enable_id_detection = true; palmas_usb->enable_vbus_detection = true; if (pdata) palmas_usb->wakeup = pdata->wakeup; } palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN); if (IS_ERR(palmas_usb->id_gpiod)) { dev_err(&pdev->dev, "failed to get id gpio\n"); return PTR_ERR(palmas_usb->id_gpiod); } palmas_usb->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus", GPIOD_IN); if (IS_ERR(palmas_usb->vbus_gpiod)) { dev_err(&pdev->dev, "failed to get vbus gpio\n"); return PTR_ERR(palmas_usb->vbus_gpiod); } if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) { palmas_usb->enable_id_detection = false; palmas_usb->enable_gpio_id_detection = true; } if (palmas_usb->enable_vbus_detection && palmas_usb->vbus_gpiod) { palmas_usb->enable_vbus_detection = false; palmas_usb->enable_gpio_vbus_detection = true; } if (palmas_usb->enable_gpio_id_detection) { u32 debounce; if (of_property_read_u32(node, "debounce-delay-ms", &debounce)) debounce = USB_GPIO_DEBOUNCE_MS; status = gpiod_set_debounce(palmas_usb->id_gpiod, debounce * 1000); if (status < 0) palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce); } INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect); palmas->usb = palmas_usb; palmas_usb->palmas = palmas; palmas_usb->dev = &pdev->dev; palmas_usb_wakeup(palmas, palmas_usb->wakeup); platform_set_drvdata(pdev, palmas_usb); palmas_usb->edev = devm_extcon_dev_allocate(&pdev->dev, palmas_extcon_cable); if (IS_ERR(palmas_usb->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); return -ENOMEM; } status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev); if (status) { dev_err(&pdev->dev, "failed to register extcon device\n"); return status; } if (palmas_usb->enable_id_detection) { palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_OTG_IRQ); palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_ID_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq, NULL, palmas_id_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_id", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->id_irq, status); return status; } } else if (palmas_usb->enable_gpio_id_detection) { palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod); if (palmas_usb->gpio_id_irq < 0) { dev_err(&pdev->dev, "failed to get id irq\n"); return palmas_usb->gpio_id_irq; } status = devm_request_threaded_irq(&pdev->dev, palmas_usb->gpio_id_irq, NULL, palmas_gpio_id_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "palmas_usb_id", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "failed to request handler for id irq\n"); return status; } } if (palmas_usb->enable_vbus_detection) { palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_OTG_IRQ); palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_vbus", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->vbus_irq, status); return status; } } else if (palmas_usb->enable_gpio_vbus_detection) { /* remux GPIO_1 as VBUSDET */ status = palmas_update_bits(palmas, PALMAS_PU_PD_OD_BASE, PALMAS_PRIMARY_SECONDARY_PAD1, PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK, (1 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)); if (status < 0) { dev_err(&pdev->dev, "can't remux GPIO1\n"); return status; } palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, PALMAS_VBUS_OTG_IRQ); palmas_usb->gpio_vbus_irq = gpiod_to_irq(palmas_usb->vbus_gpiod); if (palmas_usb->gpio_vbus_irq < 0) { dev_err(&pdev->dev, "failed to get vbus irq\n"); return palmas_usb->gpio_vbus_irq; } status = devm_request_threaded_irq(&pdev->dev, palmas_usb->gpio_vbus_irq, NULL, palmas_vbus_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "palmas_usb_vbus", palmas_usb); if (status < 0) { dev_err(&pdev->dev, "failed to request handler for vbus irq\n"); return status; } } palmas_enable_irq(palmas_usb); /* perform initial detection */ if (palmas_usb->enable_gpio_vbus_detection) palmas_vbus_irq_handler(palmas_usb->gpio_vbus_irq, palmas_usb); palmas_gpio_id_detect(&palmas_usb->wq_detectid.work); device_set_wakeup_capable(&pdev->dev, true); return 0; }