Re: [RFC v2] regmap: regmap-irq: Add main status register support

2018-12-18 Thread Matti Vaittinen
On Mon, Dec 17, 2018 at 05:32:44PM +, Mark Brown wrote:
> On Fri, Dec 14, 2018 at 04:08:12PM +0200, Matti Vaittinen wrote:
> 
> > This is draft for approach proposed by Mark here:
> > http://lkml.iu.edu/hypermail/linux/kernel/1812.1/07117.html
> 
> > Pretty untested and diff is done against tree where the level active IRQ
> > support for regmap-irq was added. So please consider this just as a RFC
> > introducing the concept. I will format correct and better tested patch if
> > this is the preferred way to go.
> 
> Hrm, so the parsing code is indeed quite complicated.  I suspect it
> could be simplified if instead of trying to allocate just what's used it
> was a bit more wasteful and allocated the biggest arrays we might need
> but I'm not sure how much that'd really help so yeah, doing it the other
> way around might be better.

It might get a little bit simpler but not much I think. And the driver
interface could be a little bit simpler if we drop the support for
giving the "main bit mapping" as an array and only support giving the
main bits in the struct regmap_irqs. Then the num_main_status_bits,
num_main_regs and sub_reg_offsets could be made internal to regmap-irq.

OTOH dropping num_main_regs would add up one more thing requiring
dynamic allocation as we could not compute the number of main register
bits in advance.

I will proceed with the RFC v1 approach. Nothing prevents us from
implementing the v2 later if there is use-cases for that. But it will
take a while before I get this thing tested and user for it.
Additionally I guess we do need a bui-in from Lee as most of this kind
of devices with many sub blocks are likely to be represented as MFD
devices. I guess I should have included him in the recipient list for
the RFCs :/

Thanks for all the support this far!

Br,
Matti Vaittinen

-- 
Matti Vaittinen
ROHM Semiconductors

~~~ "I don't think so," said Rene Descartes.  Just then, he vanished ~~~


Re: [RFC v2] regmap: regmap-irq: Add main status register support

2018-12-17 Thread Mark Brown
On Fri, Dec 14, 2018 at 04:08:12PM +0200, Matti Vaittinen wrote:

> This is draft for approach proposed by Mark here:
> http://lkml.iu.edu/hypermail/linux/kernel/1812.1/07117.html

> Pretty untested and diff is done against tree where the level active IRQ
> support for regmap-irq was added. So please consider this just as a RFC
> introducing the concept. I will format correct and better tested patch if
> this is the preferred way to go.

Hrm, so the parsing code is indeed quite complicated.  I suspect it
could be simplified if instead of trying to allocate just what's used it
was a bit more wasteful and allocated the biggest arrays we might need
but I'm not sure how much that'd really help so yeah, doing it the other
way around might be better.


signature.asc
Description: PGP signature


[RFC v2] regmap: regmap-irq: Add main status register support

2018-12-14 Thread Matti Vaittinen
There is bunch of devices with multiple logical blocks which
can generate interrupts. It's not a rare case that the interrupt
reason registers are arranged so that there is own status/ack/mask
register for each logical block. In some devices there is also a
'main interrupt register(s)' which can indicate what sub blocks
have interrupts pending.

When such a device is connected via slow bus like i2c the main
part of interrupt handling latency can be caused by bus accesses.
On systems where it is expected that only one (or few) sub blocks
have active interrupts we can reduce the latency by only reading
the main register and those sub registers which have active
interrupts. Support this with regmap-irq for simple cases where
main register does not require acking or masking.

Signed-off-by: Matti Vaittinen 
---

This is draft for approach proposed by Mark here:
http://lkml.iu.edu/hypermail/linux/kernel/1812.1/07117.html

Pretty untested and diff is done against tree where the level active IRQ
support for regmap-irq was added. So please consider this just as a RFC
introducing the concept. I will format correct and better tested patch if
this is the preferred way to go.

 drivers/base/regmap/regmap-irq.c | 276 ++-
 include/linux/regmap.h   |  61 +
 2 files changed, 332 insertions(+), 5 deletions(-)

diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index eacbb807d1c6..a3517ecd6e01 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -35,6 +35,7 @@ struct regmap_irq_chip_data {
int wake_count;
 
void *status_reg_buf;
+   unsigned int *main_status_buf;
unsigned int *status_buf;
unsigned int *mask_buf;
unsigned int *mask_buf_def;
@@ -44,6 +45,8 @@ struct regmap_irq_chip_data {
 
unsigned int irq_reg_stride;
unsigned int type_reg_stride;
+
+   struct regmap_irq_sub_irq_map *sub_irq_map;
 };
 
 static inline const
@@ -280,6 +283,32 @@ static const struct irq_chip regmap_irq_chip = {
.irq_set_wake   = regmap_irq_set_wake,
 };
 
+static inline int read_sub_irq_data(struct regmap_irq_chip_data *data,
+  unsigned int b)
+{
+   const struct regmap_irq_chip *chip = data->chip;
+   struct regmap *map = data->map;
+   int i, ret = 0;
+
+   if (!data->sub_irq_map) {
+   dev_err(map->dev, "Can't map main IRQ bit %d\n", b);
+   ret = -EINVAL;
+   } else {
+   struct regmap_irq_sub_irq_map *m;
+
+   m = >sub_irq_map[b];
+   for (i = 0; i < m->num_sub_regs; i++) {
+   unsigned int offset = m->sub_reg_offsets[i];
+
+   ret = regmap_read(map, chip->status_base + offset,
+ >status_buf[offset]);
+   if (ret)
+   break;
+   }
+   }
+   return ret;
+}
+
 static irqreturn_t regmap_irq_thread(int irq, void *d)
 {
struct regmap_irq_chip_data *data = d;
@@ -303,11 +332,70 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
}
 
/*
-* Read in the statuses, using a single bulk read if possible
-* in order to reduce the I/O overheads.
+* Read only registers with active IRQs if the chip has 'main status
+* register'. Else read in the statuses, using a single bulk read if
+* possible in order to reduce the I/O overheads.
 */
-   if (!map->use_single_read && map->reg_stride == 1 &&
-   data->irq_reg_stride == 1) {
+
+   if (chip->main_reg) {
+   unsigned int max_main_bits;
+   unsigned long size;
+
+   size = chip->num_regs * sizeof(unsigned int);
+
+   if (chip->main_reg->num_main_status_bits)
+   max_main_bits = chip->main_reg->num_main_status_bits;
+   else
+   max_main_bits = chip->main_reg->num_main_regs * 8 *
+   map->format.val_bytes;
+
+   /* Clear the status buf as we don't read all status regs */
+   memset(data->status_buf, 0, size);
+
+   /* We could support bulk read for main status registers
+* but I don't expect to see devices with really many main
+* status registers so let's only support single reads for the
+* sake of simplicity. and add bulk reads only if needed
+*/
+   for (i = 0; i < chip->main_reg->num_main_regs; i++) {
+   ret = regmap_read(map, chip->main_reg->main_status +
+ (i * map->reg_stride
+  * chip->main_reg->main_reg_stride),
+ >main_status_buf[i]);
+