From 1d843a6c8c2067615fea0ff8cb62d4a5c4a6f8ae Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Fri, 27 Jan 2012 11:35:41 +0100 Subject: mfd: ab8500-core: Allow the possibility to dump all AB8500 registers Implement an API so that a user may dump all AB8500 registers via debugfs file access. Signed-off-by: Lee Jones Signed-off-by: Mian Yousaf Kaukab Reviewed-by: Linus WALLEIJ Reviewed-by: Jonas ABERG --- drivers/mfd/ab8500-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index e1650badd106..d228697f5d9b 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -319,6 +319,7 @@ static struct abx500_ops ab8500_ops = { .mask_and_set_register = ab8500_mask_and_set_register, .event_registers_startup_state_get = NULL, .startup_irq_enabled = NULL, + .dump_all_banks = ab8500_dump_all_banks, }; static void ab8500_irq_lock(struct irq_data *data) -- cgit v1.2.3 From 8f0eb43be5f461a28341fe724686f265b0719dd3 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Tue, 14 Feb 2012 13:01:00 +0100 Subject: mfd: ab8500-debugfs: Add interrupt debug This patch adds an entry in debugfs to check number of interrupts from the AB. Signed-off-by: Lee Jones Signed-off-by: Bengt Jonsson Reviewed-by: Rabin VINCENT --- drivers/mfd/ab8500-core.c | 1 + drivers/mfd/ab8500-debugfs.c | 49 +++++++++++++++++++++++++++++++++++++++ include/linux/mfd/abx500/ab8500.h | 2 ++ 3 files changed, 52 insertions(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index d228697f5d9b..05a7af4b9768 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -521,6 +521,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev) int virq = ab8500_irq_get_virq(ab8500, line); handle_nested_irq(virq); + ab8500_debug_register_interrupt(line); value &= ~(1 << bit); } while (value); diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 8617b132e730..cbebbd7e7b40 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -736,6 +736,35 @@ static ssize_t ab8500_val_write(struct file *file, return count; } +/* + * Interrupt status + */ +static u32 num_interrupts[AB8500_MAX_NR_IRQS]; +static int num_interrupt_lines; + +void ab8500_debug_register_interrupt(int line) +{ + if (line < num_interrupt_lines) + num_interrupts[line]++; +} + +static int ab8500_interrupts_print(struct seq_file *s, void *p) +{ + int line; + + seq_printf(s, "irq: number of\n"); + + for (line = 0; line < num_interrupt_lines; line++) + seq_printf(s, "%3i: %6i\n", line, num_interrupts[line]); + + return 0; +} + +static int ab8500_interrupts_open(struct inode *inode, struct file *file) +{ + return single_open(file, ab8500_interrupts_print, inode->i_private); +} + /* * - HWREG DB8500 formated routines */ @@ -1489,6 +1518,14 @@ static const struct file_operations ab8500_val_fops = { .owner = THIS_MODULE, }; +static const struct file_operations ab8500_interrupts_fops = { + .open = ab8500_interrupts_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static const struct file_operations ab8500_subscribe_fops = { .open = ab8500_subscribe_unsubscribe_open, .write = ab8500_subscribe_write, @@ -1597,6 +1634,18 @@ static int ab8500_debug_probe(struct platform_device *plf) if (!file) goto err; + if (is_ab8500(ab8500)) + num_interrupt_lines = AB8500_NR_IRQS; + else if (is_ab8505(ab8500)) + num_interrupt_lines = AB8505_NR_IRQS; + else if (is_ab9540(ab8500)) + num_interrupt_lines = AB9540_NR_IRQS; + + file = debugfs_create_file("interrupts", (S_IRUGO), + ab8500_dir, &plf->dev, &ab8500_interrupts_fops); + if (!file) + goto err; + file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops); if (!file) diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index dbec7b00ea83..fa7173dd71f2 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -347,8 +347,10 @@ static inline int is_ab8500_2p0(struct ab8500 *ab) #ifdef CONFIG_AB8500_DEBUG void ab8500_dump_all_banks(struct device *dev); +void ab8500_debug_register_interrupt(int line); #else static inline void ab8500_dump_all_banks(struct device *dev) {} +static inline void ab8500_debug_register_interrupt(int line) {} #endif #endif /* MFD_AB8500_H */ -- cgit v1.2.3 From 9c677b9b74d4314ed7f222bf802d6d1e7585eb65 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 20 Dec 2012 11:23:42 +0000 Subject: mfd: ab8500: prepare to handle AB8500 GPIO's IRQs correctly In an upcoming patch, the gpio-ab8500 driver will relinquish all IRQ handling capability and pass it back into the AB8500 core driver. This will aid in reducing massive code duplication within the kernel. Also, most of the functionality is already in the AB8500 core driver, as the GPIO IRQs are actually sandwiched between lots of other IRQs which the core driver already handles. All we're doing here is providing the core driver with knowledge that each GPIO has two IRQs assigned to it; one for rising and a separate one for falling. Cc: Samuel Ortiz Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/ab8500-core.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 4778bb124efe..3d5da51b6a94 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -368,16 +368,40 @@ static void ab8500_irq_mask(struct irq_data *data) int mask = 1 << (offset % 8); ab8500->mask[index] |= mask; + + /* The AB8500 GPIOs have two interrupts each (rising & falling). */ + if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) + ab8500->mask[index + 2] |= mask; + if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) + ab8500->mask[index + 1] |= mask; + if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) + ab8500->mask[index] |= (mask >> 1); } static void ab8500_irq_unmask(struct irq_data *data) { struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); + unsigned int type = irqd_get_trigger_type(data); int offset = data->hwirq; int index = offset / 8; int mask = 1 << (offset % 8); - ab8500->mask[index] &= ~mask; + if (type & IRQ_TYPE_EDGE_RISING) + ab8500->mask[index] &= ~mask; + + /* The AB8500 GPIOs have two interrupts each (rising & falling). */ + if (type & IRQ_TYPE_EDGE_FALLING) { + if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) + ab8500->mask[index + 2] &= ~mask; + else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) + ab8500->mask[index + 1] &= ~mask; + else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) + ab8500->mask[index] &= ~(mask >> 1); + else + ab8500->mask[index] &= ~mask; + } else + /* Satisfies the case where type is not set. */ + ab8500->mask[index] &= ~mask; } static struct irq_chip ab8500_irq_chip = { -- cgit v1.2.3 From e2ddf46ab4ab40a657a1808cf4e358c46ae1ba68 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 6 Feb 2013 21:54:34 +0100 Subject: mfd: ab8500: actually handle the AB8500 GPIO IRQs correctly The patch: "mfd: ab8500: prepare to handle AB8500 GPIO's IRQs correctly" altered the AB8500 IRQ mask/unmask functions such that they would handle masking on/off the falling edge IRQ if this was requested by the consumer. However the bit mask for hwirqs 43 and 44 was shifting the bit mask incorrectly, resulting in the wrong IRQ being mased/unmasked. Further while the patch would mask/unmask the correct line, when the interrupt actually came in, it would still be treated as a valid hwirq. The offsetting applied when masking/unmasking was not applied when handling the IRQ, i.e. the falling edge lines were not routed back to the rising edge lines. This fixes both cases. The end result has been tested with the SIM detect IRQ, GPIO12, hwirq 46 and 62. Cc: Samuel Ortiz Cc: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/ab8500-core.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 3d5da51b6a94..6d6666b0f1b2 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -375,7 +375,8 @@ static void ab8500_irq_mask(struct irq_data *data) if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) ab8500->mask[index + 1] |= mask; if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) - ab8500->mask[index] |= (mask >> 1); + /* Here the falling IRQ is one bit lower */ + ab8500->mask[index] |= (mask << 1); } static void ab8500_irq_unmask(struct irq_data *data) @@ -396,12 +397,14 @@ static void ab8500_irq_unmask(struct irq_data *data) else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) ab8500->mask[index + 1] &= ~mask; else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) - ab8500->mask[index] &= ~(mask >> 1); + /* Here the falling IRQ is one bit lower */ + ab8500->mask[index] &= ~(mask << 1); else ab8500->mask[index] &= ~mask; - } else + } else { /* Satisfies the case where type is not set. */ ab8500->mask[index] &= ~mask; + } } static struct irq_chip ab8500_irq_chip = { @@ -435,6 +438,19 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, line = (i << 3) + int_bit; latch_val &= ~(1 << int_bit); + /* + * This handles the falling edge hwirqs from the GPIO + * lines. Route them back to the line registered for the + * rising IRQ, as this is merely a flag for the same IRQ + * in linux terms. + */ + if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) + line -= 16; + if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) + line -= 8; + if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) + line += 1; + handle_nested_irq(ab8500->irq_base + line); } while (latch_val); -- cgit v1.2.3 From 40f6e5a2b52eda7864b7167fb5af1c310b464766 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Jan 2013 12:23:48 +0000 Subject: mfd: ab8500: provide a irq_set_type() function In the AB8500 IRQ mask and unmask functions, we rely on testing for IRQ_TYPE_EDGE_RISING and IRQ_TYPE_EDGE_FALLING interrupts to physically mask and unmask the correct interrupt lines. In order for us to do that, the trigger needs to be set in the associated flags. However, unless a irq_set_type() function pointer is passed when registering the IRQ chip, the IRQ subsystem will refuse to do it. For that reason, we're providing one. Cc: Samuel Ortiz Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/ab8500-core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6d6666b0f1b2..0f1b9b788d07 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -407,6 +407,11 @@ static void ab8500_irq_unmask(struct irq_data *data) } } +static int ab8500_irq_set_type(struct irq_data *data, unsigned int type) +{ + return 0; +} + static struct irq_chip ab8500_irq_chip = { .name = "ab8500", .irq_bus_lock = ab8500_irq_lock, @@ -414,6 +419,7 @@ static struct irq_chip ab8500_irq_chip = { .irq_mask = ab8500_irq_mask, .irq_disable = ab8500_irq_mask, .irq_unmask = ab8500_irq_unmask, + .irq_set_type = ab8500_irq_set_type, }; static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, -- cgit v1.2.3 From 7d56a46e876aa89dcac921d3afab5cccace15e63 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 16 Jan 2013 14:49:45 +0000 Subject: mfd: ab8500: ensure new AB8500 pinctrl driver is probed correctly The old, BROKEN AB8500 GPIO driver has been revamped as a shiny new pinctrl driver and has been renamed as such. So, if we would like to make use of it, we need to register it via its new name. Cc: Samuel Ortiz Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/ab8500-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 0f1b9b788d07..4cb716a00178 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1097,7 +1097,7 @@ static struct mfd_cell ab8500_bm_devs[] = { static struct mfd_cell ab8500_devs[] = { { - .name = "ab8500-gpio", + .name = "pinctrl-ab8500", .of_compatible = "stericsson,ab8500-gpio", }, { -- cgit v1.2.3 From e64d905e28031031c52db403826cd3bfe060b181 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 16 Jan 2013 15:09:36 +0000 Subject: mfd: ab8500: allow AB9540 based devices to use ABX500 pinctrl The old AB8500 GPIO driver has been un-BROKEN and converted into a multi-platform pinctrl driver. If any AB9540 based devices wish to request any GPIO pins that it offers, they can after this patch. Cc: Samuel Ortiz Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/mfd/ab8500-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 4cb716a00178..e2a45abf726d 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1114,7 +1114,8 @@ static struct mfd_cell ab8500_devs[] = { static struct mfd_cell ab9540_devs[] = { { - .name = "ab8500-gpio", + .name = "pinctrl-ab9540", + .of_compatible = "stericsson,ab9540-gpio", }, { .name = "ab9540-usb", -- cgit v1.2.3 From 151621a704fc7b8eaa1d6905bec0c6388b0a57af Mon Sep 17 00:00:00 2001 From: Hongbo Zhang Date: Wed, 30 Jan 2013 18:21:27 +0800 Subject: mfd: ab8500: Rename ab8500 to abx500 for hwmon driver We are using a generic abx500 hwmon layer, so rename specific ab8500 to generic abx500 for hwmon device and driver matching. Signed-off-by: Hongbo Zhang Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mfd/ab8500-core.c') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 4778bb124efe..cdcaa5b78c4d 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -923,7 +923,7 @@ static struct resource ab8505_iddet_resources[] = { static struct resource ab8500_temp_resources[] = { { - .name = "AB8500_TEMP_WARM", + .name = "ABX500_TEMP_WARM", .start = AB8500_INT_TEMP_WARM, .end = AB8500_INT_TEMP_WARM, .flags = IORESOURCE_IRQ, @@ -999,8 +999,8 @@ static struct mfd_cell abx500_common_devs[] = { .of_compatible = "stericsson,ab8500-denc", }, { - .name = "ab8500-temp", - .of_compatible = "stericsson,ab8500-temp", + .name = "abx500-temp", + .of_compatible = "stericsson,abx500-temp", .num_resources = ARRAY_SIZE(ab8500_temp_resources), .resources = ab8500_temp_resources, }, -- cgit v1.2.3