From: Peter Rosin <peda@axentia.se>
To: Phil Reid <preid@electromag.com.au>,
wsa@the-dreams.de, linux-i2c@vger.kernel.org
Subject: Re: [RFC PATCH 1/1] i2c: i2c-mux-pca954x: Add interrupt controller support.
Date: Wed, 27 Jul 2016 07:32:05 +0200 [thread overview]
Message-ID: <e96c68d6-7905-7bee-2173-b66d29e9969b@axentia.se> (raw)
In-Reply-To: <1469588756-70579-2-git-send-email-preid@electromag.com.au>
On 2016-07-27 05:05, Phil Reid wrote:
> 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>
Please keep the includes sorted.
> #define PCA954X_MAX_NCHANS 8
>
> +#define PCA9543_IRQ_OFFSET 4
PCA9544 and PCA9545 also support interrupts, and they look similar.
It would be preferable if the changes accommodated the other chips
supported by the driver. They all look similar, and the irq bits
looks like they are always in the same place, but I think I would
like this offset to go into the chip_desc struct all the same.
At the very least the define should be renamed PCA954X_IRQ_OFFSET.
> +
> 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++) {
Please use nchans instead of 2 here.
> + 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)
The 0x3 mask should probably also go into struct chip_desc, then a non-
empty value in this field could be used as trigger for initing the irq
stuff.
> + 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)
This is what you mentioned in the commit message, but I don't get it.
Please explain further, and also think about how the same problem
could be handled should there be 4 incoming irq lines as in pca9544
and pca9545.
> + 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)
This function should be named pca954x_irq_domain_map.
> +{
> + 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 = {
This constant should be named pca954x_irq_domain_ops.
> + .map = pca953x_irq_domain_map,
> + .xlate = irq_domain_xlate_twocell,
> +};
> +
> +static int pca953x_irq_setup(struct i2c_mux_core *muxc)
This function should be named pca954x_irq_setup.
> +{
> + 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;
So here, please use the new irq mask value (0x3) that I proposed
above, instead of the explicitly check for pca9543.
> + 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++)
nchans instead of 2, two instances I guess? I know very little about kernel
interrupt handling and can't really say anything about if your code interfacing
the irq subsystem is good to go...
> + 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;
>
Cheers,
Peter
next prev parent reply other threads:[~2016-07-27 14:05 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 ` [RFC PATCH 1/1] " Phil Reid
2016-07-27 5:32 ` Peter Rosin [this message]
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=e96c68d6-7905-7bee-2173-b66d29e9969b@axentia.se \
--to=peda@axentia.se \
--cc=linux-i2c@vger.kernel.org \
--cc=preid@electromag.com.au \
--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).