Thread (19 messages) 19 messages, 4 authors, 2011-07-08

[Qualcomm PM8921 MFD 2/6] mfd: pm8xxx: Add irq support

From: Abhijeet Dharmapurikar <hidden>
Date: 2011-03-03 04:38:07
Also in: linux-arm-msm, lkml

Mark Brown wrote:
On Wed, Mar 02, 2011 at 02:13:17PM -0800, adharmap at codeaurora.org wrote:
quoted
Change-Id: Ibb23878cd382af9a750d62ab49482f5dc72e3714
Signed-off-by: Abhijeet Dharmapurikar <redacted>
Remove the change IDs from upstream submissions.  The kernel doesn't use
gerritt.
quoted
 struct pm8921 {
-	struct device *dev;
+	struct device			*dev;
+	struct device			*irq_dev;
Is it really useful to register a struct device purely for the interrupt
controller?  I'd have expected this to be core functionality of the
device.  The fact that you need to store the device at all is a bit odd
too as you're using the MFD API.
This design is slightly different from other MFD drivers.
I separated the interrupt from the core because the interrupt 
implementation for different Qualcomm pmics remains the same. On 8660 
FFA boards for example, we have two pmic chips that have the same 
interrupt subdevice implementation (the number of interrupts managed by 
each is different). I didn't want to duplicate the exact code in the 
core driver - hence a separate interrupt driver.

To answer why we need to keep a reference to irq_dev. This is so because 
the gpio code needs to make calls on the irq driver to read the input 
values. The gpio code calls pm8xxx_read_irq_stat() on the core and 
expects it to read the value. The core then calls an api in the irq 
driver (pm8xxx_get_irq_stat)passing it irq_dev to get the required values.

I could have made the gpio code call the irq code directly, but then 
that would mean the irq driver has to go over all its devices and find 
which device handles this irq number and then read it. That is too much 
code execution as compared to remember the irq_dev for each core and let 
the gpio code call read apis on it.
quoted
 static struct pm8xxx_drvdata pm8921_drvdata = {
-	.pmic_readb	= pm8921_readb,
-	.pmic_writeb	= pm8921_writeb,
-	.pmic_read_buf	= pm8921_read_buf,
-	.pmic_write_buf = pm8921_write_buf,
+	.pmic_readb		= pm8921_readb,
+	.pmic_writeb		= pm8921_writeb,
+	.pmic_read_buf		= pm8921_read_buf,
+	.pmic_write_buf		= pm8921_write_buf,
+	.pmic_read_irq_stat	= pm8921_read_irq_stat,
+};
It'd seem better to indent things as per the final driver in the first
patch - this reindentation creates a lot of noise in the diff.
quoted
 		goto err_read_rev;
 	}
-	pr_info("PMIC revision:   %02X\n", val);
+	pr_info("PMIC revision 1: %02X\n", val);
+	rev = val;
Yes will fix them
quoted
 
Again, do this in the first patch.
quoted
+static int
+pm8xxx_read_block(const struct pm_irq_chip *chip, u8 bp, u8 *ip)
+{
+	int	rc;
+
+	rc = pm8xxx_writeb(chip->dev->parent,
+				SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+	if (rc) {
+		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+		goto bail_out;
+	}
+
+	rc = pm8xxx_readb(chip->dev->parent,
+			SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+	if (rc)
+		pr_err("Failed Reading Status rc=%d\n", rc);
+bail_out:
+	return rc;
+}
The namespacing here is odd, this looks like it should be a generic API
not a block specific one.
It indicates that the code intends to read a block of interrupt 
statuses. The irq h/w is implemented as follows, there are 256 
interrupts. One block manages 8 interrupts, so there are 32 blocks.
One master manages 8 blocks so there are 4 masters.  And finally there 
is one root that manages all the 4 masters.

When an interrupt triggers, the corresponding bit in the block, master 
and root is set. The handler reads the root and figures out which master 
is set. It then reads the master and figures out which block in that 
master is set. It then reads the block to figure out which interrupt in 
that block is set. This hardware design makes the handler find the 
interrupt super quick as opposed to checking 256 bits when an interrupt 
fires.

With that in mind, the driver has following functions
pm8xxxx_read_root
pm8xxxx_read_master
pm8xxxx_read_block

Do you still think I should change the name?
quoted
+	/* Check IRQ bits */
+	for (k = 0; k < 8; k++) {
+		if (bits & (1 << k)) {
+			pmirq = block * 8 + k;
+			irq = pmirq + chip->irq_base;
+			/* Check spurious interrupts */
+			if (((1 << k) & chip->irqs_allowed[block])) {
+				/* Found one */
+				chip->irqs_to_handle[*handled] = irq;
+				(*handled)++;
+			} else { /* Clear and mask wrong one */
+				config = PM_IRQF_W_C_M |
+					(k << PM_IRQF_BITS_SHIFT);
+
+				pm8xxx_config_irq(chip,
+						  block, config);
+
+				if (pm8xxx_can_print())
+					pr_err("Spurious IRQ: %d "
+					       "[block, bit]="
+					       "[%d, %d]\n",
+					       irq, block, k);
+			}
The generic IRQ code should be able to take care of spurious interrupts
for you?  It's a bit surprising that there's all this logic - I'd expect
an IRQ chip to just defer logic about which interrupts are valid and so
on to the generic IRQ code.
That is correct, the genirq does handle spurious interrupts gracefully. 
Will fix this in the next patch series.
quoted
+
+#define NR_PM8921_IRQS 256
Traditionally this'd be namespaced like this:

+#define PM8921_NR_IRQS 256
ok good to know will change that.

--
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm 
Innovation Center, Inc. is a member of the Code Aurora Forum.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help