linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Phil Reid <preid@electromag.com.au>
To: wsa@the-dreams.de, peda@axentia.se, linux-i2c@vger.kernel.org
Cc: Phil Reid <preid@electromag.com.au>
Subject: [RFC PATCH 1/1] i2c: i2c-mux-pca954x: Add interrupt controller support.
Date: Wed, 27 Jul 2016 11:05:56 +0800	[thread overview]
Message-ID: <1469588756-70579-2-git-send-email-preid@electromag.com.au> (raw)
In-Reply-To: <1469588756-70579-1-git-send-email-preid@electromag.com.au>

The pca9543 can aggregate multiple interrupts from each i2c bus.
However it provides no ability to mask interrupts on each channel.
So if one bus is asserting interrupts than it will continuously
trigger the interrupts until another driver clears it. As a
workaround don't enable interrupts until both irqs have been unmasked.

Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 116 ++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 284e342..9ff2540 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -45,9 +45,14 @@
 #include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
 
 #define PCA954X_MAX_NCHANS 8
 
+#define PCA9543_IRQ_OFFSET 4
+
 enum pca_type {
 	pca_9540,
 	pca_9542,
@@ -67,6 +72,8 @@ struct pca954x {
 	struct i2c_client *client;
 	bool idle_reset;
 	struct gpio_desc *gpio;
+	struct irq_domain *irq_domain;
+	unsigned int irq_mask;
 };
 
 struct chip_desc {
@@ -194,6 +201,110 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
 	return pca954x_reg_write(muxc->parent, client, data->last_chan);
 }
 
+static irqreturn_t pca954x_irq_handler(int irq, void *devid)
+{
+	struct pca954x *data = i2c_mux_priv(devid);
+	struct i2c_client *client = data->client;
+	int i, ret, child_irq;
+	unsigned int nhandled = 0;
+
+	ret = i2c_smbus_read_byte(client);
+	if (ret < 0)
+		return IRQ_NONE;
+
+	for (i = 0; i < 2; i++) {
+		if (ret & BIT(PCA9543_IRQ_OFFSET+i)) {
+			child_irq = irq_find_mapping(data->irq_domain, i);
+			handle_nested_irq(child_irq);
+			nhandled++;
+		}
+	}
+
+	return (nhandled > 0) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void pca954x_irq_mask(struct irq_data *idata)
+{
+	struct i2c_mux_core *muxc = irq_data_get_irq_chip_data(idata);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	unsigned int pos = idata->hwirq;
+
+	data->irq_mask &= ~BIT(pos);
+	if ((data->irq_mask & 0x3) != 0)
+		disable_irq(data->client->irq);
+}
+
+static void pca954x_irq_unmask(struct irq_data *idata)
+{
+	struct i2c_mux_core *muxc = irq_data_get_irq_chip_data(idata);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	unsigned int pos = idata->hwirq;
+
+	data->irq_mask |= ~BIT(pos);
+	if ((data->irq_mask & 0x3) == 0x3)
+		enable_irq(data->client->irq);
+}
+
+static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
+{
+	return 0;
+}
+
+static struct irq_chip pca954x_irq_chip = {
+	.name			= "i2c-mux-pca954x",
+	.irq_mask = pca954x_irq_mask,
+	.irq_unmask = pca954x_irq_unmask,
+	.irq_set_type = pca954x_irq_set_type,
+};
+
+static int pca953x_irq_domain_map(struct irq_domain *h, unsigned int irq,
+				 irq_hw_number_t hwirq)
+{
+	struct i2c_mux_core *muxc = h->host_data;
+
+	irq_set_chip_data(irq, muxc);
+	irq_set_chip_and_handler(irq, &pca954x_irq_chip, handle_level_irq);
+	return 0;
+}
+
+static const struct irq_domain_ops pca953x_irq_domain_ops = {
+	.map	= pca953x_irq_domain_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
+static int pca953x_irq_setup(struct i2c_mux_core *muxc)
+{
+	struct pca954x *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
+	int i, ret;
+	int irq = client->irq;
+
+	if ((data->type != pca_9543) && (irq != -1))
+		return 0;
+
+	ret = devm_request_threaded_irq(&client->dev, irq, NULL,
+					pca954x_irq_handler,
+					IRQF_TRIGGER_HIGH | IRQF_ONESHOT |
+					   IRQF_SHARED,
+					dev_name(&client->dev), muxc);
+	if (ret) {
+		dev_err(&client->dev, "failed to request irq %d %d\n",
+			client->irq, ret);
+		return ret;
+	}
+
+	disable_irq(irq);
+
+	data->irq_domain = irq_domain_add_simple(client->dev.of_node,
+						 2, 0, &pca953x_irq_domain_ops,
+						 muxc);
+
+	for (i = 0; i < 2; i++)
+		irq_set_parent(irq_find_mapping(data->irq_domain, i), irq);
+
+	return 0;
+}
+
 /*
  * I2C init/probing/exit functions
  */
@@ -274,6 +385,10 @@ static int pca954x_probe(struct i2c_client *client,
 		}
 	}
 
+	ret = pca953x_irq_setup(muxc);
+	if (ret)
+		goto irq_setup_failed;
+
 	dev_info(&client->dev,
 		 "registered %d multiplexed busses for I2C %s %s\n",
 		 num, chips[data->type].muxtype == pca954x_ismux
@@ -281,6 +396,7 @@ static int pca954x_probe(struct i2c_client *client,
 
 	return 0;
 
+irq_setup_failed:
 virt_reg_failed:
 	i2c_mux_del_adapters(muxc);
 	return ret;
-- 
1.8.3.1

  reply	other threads:[~2016-07-27  3:14 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-27  3:05 [RFC PATCH 0/1] i2c: i2c-mux-pca954x: Add interrupt controller support Phil Reid
2016-07-27  3:05 ` Phil Reid [this message]
2016-07-27  5:32   ` [RFC PATCH 1/1] " Peter Rosin
2016-07-28  2:44     ` Phil Reid
2016-07-29  5:48       ` Peter Rosin
2016-08-01  6:25         ` Phil Reid
2016-08-01  8:22           ` Peter Rosin
2016-08-01  8:52             ` Phil Reid

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=1469588756-70579-2-git-send-email-preid@electromag.com.au \
    --to=preid@electromag.com.au \
    --cc=linux-i2c@vger.kernel.org \
    --cc=peda@axentia.se \
    --cc=wsa@the-dreams.de \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).