|
@@ -57,6 +57,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
|
|
|
if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
|
|
|
palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
|
|
|
extcon_set_cable_state(&palmas_usb->edev, "USB", true);
|
|
|
+ dev_info(palmas_usb->dev, "USB cable is attached\n");
|
|
|
} else {
|
|
|
dev_dbg(palmas_usb->dev,
|
|
|
"Spurious connect event detected\n");
|
|
@@ -65,6 +66,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
|
|
|
if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
|
|
|
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
|
|
|
extcon_set_cable_state(&palmas_usb->edev, "USB", false);
|
|
|
+ dev_info(palmas_usb->dev, "USB cable is detached\n");
|
|
|
} else {
|
|
|
dev_dbg(palmas_usb->dev,
|
|
|
"Spurious disconnect event detected\n");
|
|
@@ -83,29 +85,24 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
|
|
|
PALMAS_USB_ID_INT_LATCH_SET, &set);
|
|
|
|
|
|
if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
|
|
|
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
|
|
|
- PALMAS_USB_ID_INT_EN_HI_SET,
|
|
|
- PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
|
|
|
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
|
|
|
- PALMAS_USB_ID_INT_EN_HI_CLR,
|
|
|
- PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
|
|
|
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
|
|
|
PALMAS_USB_ID_INT_LATCH_CLR,
|
|
|
PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
|
|
|
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
|
|
|
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
|
|
|
+ dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
|
|
|
} else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
|
|
|
- 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_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
|
|
|
- PALMAS_USB_ID_INT_EN_HI_CLR,
|
|
|
- PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
|
|
|
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
|
|
|
PALMAS_USB_ID_INT_LATCH_CLR,
|
|
|
PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
|
|
|
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
|
|
|
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
|
|
|
+ dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
|
|
|
+ } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
|
|
|
+ (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
|
|
|
+ palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
|
|
|
+ extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
|
|
|
+ dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
|
|
|
}
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
@@ -122,13 +119,17 @@ static void palmas_enable_irq(struct palmas_usb *palmas_usb)
|
|
|
|
|
|
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_GND |
|
|
|
+ PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
|
|
|
|
|
|
- palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
|
|
|
+ if (palmas_usb->enable_vbus_detection)
|
|
|
+ palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
|
|
|
|
|
|
/* cold plug for host mode needs this delay */
|
|
|
- msleep(30);
|
|
|
- palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
|
|
|
+ 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)
|
|
@@ -139,21 +140,25 @@ static int palmas_usb_probe(struct platform_device *pdev)
|
|
|
struct palmas_usb *palmas_usb;
|
|
|
int status;
|
|
|
|
|
|
- if (node && !pdata) {
|
|
|
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
-
|
|
|
- if (!pdata)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- pdata->wakeup = of_property_read_bool(node, "ti,wakeup");
|
|
|
- } else if (!pdata) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
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 = palmas_usb;
|
|
|
palmas_usb->palmas = palmas;
|
|
|
|
|
@@ -168,11 +173,10 @@ static int palmas_usb_probe(struct platform_device *pdev)
|
|
|
palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
|
|
|
PALMAS_VBUS_IRQ);
|
|
|
|
|
|
- palmas_usb_wakeup(palmas, pdata->wakeup);
|
|
|
+ palmas_usb_wakeup(palmas, palmas_usb->wakeup);
|
|
|
|
|
|
platform_set_drvdata(pdev, palmas_usb);
|
|
|
|
|
|
- palmas_usb->edev.name = "palmas-usb";
|
|
|
palmas_usb->edev.supported_cable = palmas_extcon_cable;
|
|
|
palmas_usb->edev.mutually_exclusive = mutually_exclusive;
|
|
|
|
|
@@ -182,28 +186,36 @@ static int palmas_usb_probe(struct platform_device *pdev)
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
- status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq,
|
|
|
- NULL, palmas_id_irq_handler,
|
|
|
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
|
|
- "palmas_usb_id", palmas_usb);
|
|
|
- if (status < 0) {
|
|
|
- dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
|
|
|
+ if (palmas_usb->enable_id_detection) {
|
|
|
+ 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 | IRQF_EARLY_RESUME,
|
|
|
+ "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);
|
|
|
- goto fail_extcon;
|
|
|
+ goto fail_extcon;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- status = devm_request_threaded_irq(palmas_usb->dev,
|
|
|
- palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler,
|
|
|
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
|
|
- "palmas_usb_vbus", palmas_usb);
|
|
|
- if (status < 0) {
|
|
|
- dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
|
|
|
+ if (palmas_usb->enable_vbus_detection) {
|
|
|
+ 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 | IRQF_EARLY_RESUME,
|
|
|
+ "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);
|
|
|
- goto fail_extcon;
|
|
|
+ goto fail_extcon;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
palmas_enable_irq(palmas_usb);
|
|
|
-
|
|
|
+ device_set_wakeup_capable(&pdev->dev, true);
|
|
|
return 0;
|
|
|
|
|
|
fail_extcon:
|
|
@@ -221,6 +233,39 @@ static int palmas_usb_remove(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
|
+static int palmas_usb_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ if (device_may_wakeup(dev)) {
|
|
|
+ if (palmas_usb->enable_vbus_detection)
|
|
|
+ enable_irq_wake(palmas_usb->vbus_irq);
|
|
|
+ if (palmas_usb->enable_id_detection)
|
|
|
+ enable_irq_wake(palmas_usb->id_irq);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int palmas_usb_resume(struct device *dev)
|
|
|
+{
|
|
|
+ struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ if (device_may_wakeup(dev)) {
|
|
|
+ if (palmas_usb->enable_vbus_detection)
|
|
|
+ disable_irq_wake(palmas_usb->vbus_irq);
|
|
|
+ if (palmas_usb->enable_id_detection)
|
|
|
+ disable_irq_wake(palmas_usb->id_irq);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+static const struct dev_pm_ops palmas_pm_ops = {
|
|
|
+ SET_SYSTEM_SLEEP_PM_OPS(palmas_usb_suspend,
|
|
|
+ palmas_usb_resume)
|
|
|
+};
|
|
|
+
|
|
|
static struct of_device_id of_palmas_match_tbl[] = {
|
|
|
{ .compatible = "ti,palmas-usb", },
|
|
|
{ .compatible = "ti,twl6035-usb", },
|
|
@@ -234,6 +279,7 @@ static struct platform_driver palmas_usb_driver = {
|
|
|
.name = "palmas-usb",
|
|
|
.of_match_table = of_palmas_match_tbl,
|
|
|
.owner = THIS_MODULE,
|
|
|
+ .pm = &palmas_pm_ops,
|
|
|
},
|
|
|
};
|
|
|
|