All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ivo Manca <pinkel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>,
	"Mark M. Hoffman"
	<mhoffman-xQSgfq/1h4JiLUuM0BA3LQ@public.gmane.org>
Cc: Hans de Goede <j.w.r.degoede-fbo2DhPpy/Q@public.gmane.org>,
	i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
Subject: [PATCH 01/03] i2c-i801: Add basic interrupt support
Date: Wed, 23 Jul 2008 18:56:40 +0200	[thread overview]
Message-ID: <488762C8.6090105@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 144 bytes --]

This patch adds basic interrupt support to the i2c-i801 driver.

Signed-off-by: Ivo Manca <pinkel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---


[-- Attachment #2: patch1.diff --]
[-- Type: text/plain, Size: 5450 bytes --]

--- i2c-i801.c.git	2008-07-03 15:47:32.000000000 +0200
+++ i2c-i801.c	2008-07-07 15:04:25.000000000 +0200
@@ -63,6 +63,7 @@
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <asm/io.h>
 
@@ -100,6 +101,7 @@
 
 /* I801 command constants */
 #define I801_QUICK		0x00
+#define I801_HST_CNT_INTREN	0x01
 #define I801_BYTE		0x04
 #define I801_BYTE_DATA		0x08
 #define I801_WORD_DATA		0x0C
@@ -121,23 +123,65 @@
 #define SMBHSTSTS_INTR		0x02
 #define SMBHSTSTS_HOST_BUSY	0x01
 
+/* mask for events we normally handle */
+#define I801_HST_STS_MASK_NORM ( \
+		SMBHSTSTS_FAILED | \
+		SMBHSTSTS_BUS_ERR | \
+		SMBHSTSTS_DEV_ERR | \
+		SMBHSTSTS_INTR)
+
+/* mask for all events */
+#define I801_HST_STS_MASK_ALL ( \
+		SMBHSTSTS_BYTE_DONE | \
+		SMBHSTSTS_SMBALERT_STS | \
+		SMBHSTSTS_FAILED | \
+		SMBHSTSTS_BUS_ERR | \
+		SMBHSTSTS_DEV_ERR | \
+		SMBHSTSTS_INTR)
+
 static unsigned long i801_smba;
 static unsigned char i801_original_hstcfg;
+static struct i2c_adapter i801_adapter;
 static struct pci_driver i801_driver;
 static struct pci_dev *I801_dev;
 
+struct i2c_i801_algo_data {
+	spinlock_t lock;
+	wait_queue_head_t waitq;
+	int status; /* copy of h/w register */
+	int irq;
+};
+
+static struct i2c_i801_algo_data i801_algo_data;
+
 #define FEATURE_SMBUS_PEC	(1 << 0)
 #define FEATURE_BLOCK_BUFFER	(1 << 1)
 #define FEATURE_BLOCK_PROC	(1 << 2)
 #define FEATURE_I2C_BLOCK_READ	(1 << 3)
 static unsigned int i801_features;
 
+/* fetch & consume host status out of algo_data */
+static inline int i801_get_status(struct i2c_i801_algo_data *algo_data)
+{
+	unsigned long flags;
+	int status;
+
+	spin_lock_irqsave(&algo_data->lock, flags);
+	status = algo_data->status;
+	algo_data->status = 0;
+	spin_unlock_irqrestore(&algo_data->lock, flags);
+
+	return status;
+}
+
 static int i801_transaction(int xact)
 {
 	int temp;
 	int result = 0;
 	int timeout = 0;
 
+	struct i2c_i801_algo_data *algo_data = i801_adapter.algo_data;
+
 	dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
@@ -159,6 +203,13 @@ static int i801_transaction(int xact)
 
 	/* the current contents of SMBHSTCNT can be overwritten, since PEC,
 	 * INTREN, SMBSCMD are passed in xact */
+	if (algo_data->irq >= 0) {
+		outb_p(xact | I801_START | I801_HST_CNT_INTREN, SMBHSTCNT);
+
+		wait_event_interruptible_timeout(algo_data->waitq,
+					((temp = i801_get_status(algo_data))
+					& I801_HST_STS_MASK_NORM), HZ/2);
+	} else {
 	outb_p(xact | I801_START, SMBHSTCNT);
 
 	/* We will always wait for a fraction of a second! */
@@ -177,6 +228,7 @@ static int i801_transaction(int xact)
 		msleep(1);
 		outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
 	}
+	}
 
 	if (temp & SMBHSTSTS_FAILED) {
 		result = -1;
@@ -574,6 +626,7 @@ static struct i2c_adapter i801_adapter =
 	.id		= I2C_HW_SMBUS_I801,
 	.class		= I2C_CLASS_HWMON,
 	.algo		= &smbus_algorithm,
+	.algo_data	= &i801_algo_data
 };
 
 static struct pci_device_id i801_ids[] = {
@@ -597,8 +650,38 @@ static struct pci_device_id i801_ids[] =
 
 MODULE_DEVICE_TABLE (pci, i801_ids);
 
+static irqreturn_t i801_isr(int irq, void *dev_id)
+{
+	u8 status = inb(SMBHSTSTS);
+
+	/* bail if it's not ours */
+	if (!(status & I801_HST_STS_MASK_ALL)) {
+		dev_dbg(&I801_dev->dev, "BAILING interrupt\n");
+		return IRQ_NONE;
+	}
+
+	dev_dbg(&I801_dev->dev, "INTERRUPT: IRQ status: 0x%02x\n", status);
+
+	/* ACK */
+	outb((status & I801_HST_STS_MASK_ALL), SMBHSTSTS);
+
+	if (status & I801_HST_STS_MASK_NORM) {
+		struct i2c_adapter *adap = dev_id;
+		struct i2c_i801_algo_data *algo_data = adap->algo_data;
+		unsigned long flags;
+
+		spin_lock_irqsave(&algo_data->lock, flags);
+		algo_data->status = status;
+		spin_unlock_irqrestore(&algo_data->lock, flags);
+		wake_up_interruptible(&algo_data->waitq);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
+	struct i2c_i801_algo_data *algo_data = i801_adapter.algo_data;
 	unsigned char temp;
 	int err;
 
@@ -656,10 +739,27 @@ static int __devinit i801_probe(struct p
 	}
 	pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
 
-	if (temp & SMBHSTCFG_SMB_SMI_EN)
+	if (temp & SMBHSTCFG_SMB_SMI_EN) {
 		dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
-	else
+		algo_data->irq = -1;
+	} else {
 		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
+		if ((request_irq(I801_dev->irq, i801_isr, IRQF_SHARED,
+				 i801_adapter.name, &i801_adapter))) {
+			dev_err(&dev->dev,
+				"request irq %d failed!\n", I801_dev->irq);
+			algo_data->irq = -1;
+		} else {
+			dev_dbg(&dev->dev,
+				"SMBus base address: 0x%04lx, IRQ: %d\n",
+				i801_smba, I801_dev->irq);
+
+			algo_data->irq = I801_dev->irq;
+			algo_data->status = 0;
+			init_waitqueue_head(&algo_data->waitq);
+			spin_lock_init(&algo_data->lock);
+		}
+	}
 
 	/* Clear special mode bits */
 	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
@@ -686,6 +786,10 @@ exit:
 
 static void __devexit i801_remove(struct pci_dev *dev)
 {
+	struct i2c_i801_algo_data *algo_data = i801_adapter.algo_data;
+	if (algo_data->irq >= 0)
+		free_irq(dev->irq, &i801_adapter);
+
 	i2c_del_adapter(&i801_adapter);
 	pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg);
 	pci_release_region(dev, SMBBAR);

[-- Attachment #3: Type: text/plain, Size: 157 bytes --]

_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c

             reply	other threads:[~2008-07-23 16:56 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-23 16:56 Ivo Manca [this message]
     [not found] ` <488762C8.6090105-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2008-08-12  8:15   ` [PATCH 01/03] i2c-i801: Add basic interrupt support Jean Delvare
     [not found]     ` <20080812101545.600ca850-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-08-13 19:17       ` Ivo Manca
     [not found]         ` <48A33342.1050105-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2008-08-13 19:59           ` Ivo Manca
2008-08-13 20:38           ` Jean Delvare

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=488762C8.6090105@gmail.com \
    --to=pinkel-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
    --cc=i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org \
    --cc=j.w.r.degoede-fbo2DhPpy/Q@public.gmane.org \
    --cc=khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org \
    --cc=mhoffman-xQSgfq/1h4JiLUuM0BA3LQ@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.