[PATCH] twl4030-usb: add handler for unmasked events

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Handler for VBUS pin monitor events.
Notify sysfs on vbus level change.
Return error if creating sysfs files fails.

Signed-off-by: Krogerus Heikki (EXT-Teleca/Helsinki) <ext-heikki.krogerus@xxxxxxxxx>
---
 drivers/usb/otg/twl4030-usb.c |   64 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 416e441..0ffe02b 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -256,6 +256,7 @@ struct twl4030_usb {
 	u8			linkstat;
 	u8			asleep;
 	bool			irq_enabled;
+	u8			irq_source;
 };
 
 /* internal define on top of container_of */
@@ -339,6 +340,17 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 
 /*-------------------------------------------------------------------------*/
 
+const char *twl4030_vbusevent_string(struct twl4030_usb *twl)
+{
+	if (twl->irq_source & USB_INT_SESSEND)
+		return "sessend";
+	else if (twl->irq_source & USB_INT_SESSVALID)
+		return "sessvalid";
+	else if (twl->irq_source & USB_INT_VBUSVALID)
+		return "vbusvalid";
+	return "noevent";
+}
+
 static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
 {
 	int	status;
@@ -512,6 +524,36 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev,
 }
 static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
 
+static ssize_t twl4030_usb_vbusevent_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct twl4030_usb *twl = dev_get_drvdata(dev);
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&twl->lock, flags);
+	ret = sprintf(buf, "%s\n", twl4030_vbusevent_string(twl));
+	spin_unlock_irqrestore(&twl->lock, flags);
+
+	return ret;
+}
+static DEVICE_ATTR(vbusevent, 0444, twl4030_usb_vbusevent_show, NULL);
+
+static void twl4030_vbusevent(struct twl4030_usb *twl)
+{
+	/* Handle unmasked events. See the levels from the TRM.
+	 *
+	 * Condition				USB_INT_STS/LATCH
+	 * ----------------------------------------------------------
+	 * VBUS < VSESSEND			USB_INT_SESSEND
+	 * VSESSVALID <= VBUS < VBUSVALID	USB_INT_SESSVALID
+	 * VBUSVALID <= VBUS			USB_INT_VBUSVALID
+	 *
+	 * REVISIT call power management as needed.
+	 */
+	sysfs_notify(&twl->dev->kobj, NULL, "vbusevent");
+}
+
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
 	struct twl4030_usb *twl = _twl;
@@ -525,6 +567,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 	local_irq_enable();
 #endif
 
+	twl->irq_source = twl4030_usb_read(twl, USB_INT_STS);
+	if (twl->irq_source) {
+		twl4030_vbusevent(twl);
+		goto vbus_event;
+	}
+
 	status = twl4030_usb_linkstat(twl);
 	if (status != USB_LINK_UNKNOWN) {
 
@@ -548,6 +596,7 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 	}
 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 
+vbus_event:
 	return IRQ_HANDLED;
 }
 
@@ -626,8 +675,18 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
 	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");
+	err = device_create_file(&pdev->dev, &dev_attr_vbus);
+	if (err) {
+		dev_err(&pdev->dev, "could not create sysfs file \"vbus\"\n");
+		kfree(twl);
+		return err;
+	}
+	err = device_create_file(&pdev->dev, &dev_attr_vbusevent);
+	if (err) {
+		dev_err(&pdev->dev, "could not create sysfs file \"vbusevent\"\n");
+		kfree(twl);
+		return err;
+	}
 
 	/* Our job is to use irqs and status from the power module
 	 * to keep the transceiver disabled when nothing's connected.
@@ -669,6 +728,7 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
 
 	free_irq(twl->irq, twl);
 	device_remove_file(twl->dev, &dev_attr_vbus);
+	device_remove_file(twl->dev, &dev_attr_vbusevent);
 
 	/* set transceiver mode to power on defaults */
 	twl4030_usb_set_mode(twl, -1);
-- 
1.6.0.6

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux