regmap: irq: Enable devices for runtime PM while handling interrupts
Some devices need to have a runtime PM reference while handling interrupts to ensure that the register I/O is available. Support this with a flag in the chip. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
		
					parent
					
						
							
								40052ca0c2
							
						
					
				
			
			
				commit
				
					
						0c00c50b41
					
				
			
		
					 2 changed files with 27 additions and 0 deletions
				
			
		| 
						 | 
					@ -16,6 +16,7 @@
 | 
				
			||||||
#include <linux/irq.h>
 | 
					#include <linux/irq.h>
 | 
				
			||||||
#include <linux/interrupt.h>
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
#include <linux/irqdomain.h>
 | 
					#include <linux/irqdomain.h>
 | 
				
			||||||
 | 
					#include <linux/pm_runtime.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "internal.h"
 | 
					#include "internal.h"
 | 
				
			||||||
| 
						 | 
					@ -62,6 +63,13 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
 | 
				
			||||||
	int i, ret;
 | 
						int i, ret;
 | 
				
			||||||
	u32 reg;
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (d->chip->runtime_pm) {
 | 
				
			||||||
 | 
							ret = pm_runtime_get_sync(map->dev);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								dev_err(map->dev, "IRQ sync failed to resume: %d\n",
 | 
				
			||||||
 | 
									ret);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If there's been a change in the mask write it back to the
 | 
						 * If there's been a change in the mask write it back to the
 | 
				
			||||||
	 * hardware.  We rely on the use of the regmap core cache to
 | 
						 * hardware.  We rely on the use of the regmap core cache to
 | 
				
			||||||
| 
						 | 
					@ -77,6 +85,9 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
 | 
				
			||||||
				reg);
 | 
									reg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (d->chip->runtime_pm)
 | 
				
			||||||
 | 
							pm_runtime_put(map->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If we've changed our wakeup count propagate it to the parent */
 | 
						/* If we've changed our wakeup count propagate it to the parent */
 | 
				
			||||||
	if (d->wake_count < 0)
 | 
						if (d->wake_count < 0)
 | 
				
			||||||
		for (i = d->wake_count; i < 0; i++)
 | 
							for (i = d->wake_count; i < 0; i++)
 | 
				
			||||||
| 
						 | 
					@ -147,6 +158,15 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 | 
				
			||||||
	bool handled = false;
 | 
						bool handled = false;
 | 
				
			||||||
	u32 reg;
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (chip->runtime_pm) {
 | 
				
			||||||
 | 
							ret = pm_runtime_get_sync(map->dev);
 | 
				
			||||||
 | 
							if (ret < 0) {
 | 
				
			||||||
 | 
								dev_err(map->dev, "IRQ thread failed to resume: %d\n",
 | 
				
			||||||
 | 
									ret);
 | 
				
			||||||
 | 
								return IRQ_NONE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Ignore masked IRQs and ack if we need to; we ack early so
 | 
						 * Ignore masked IRQs and ack if we need to; we ack early so
 | 
				
			||||||
	 * there is no race between handling and acknowleding the
 | 
						 * there is no race between handling and acknowleding the
 | 
				
			||||||
| 
						 | 
					@ -162,6 +182,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 | 
				
			||||||
		if (ret != 0) {
 | 
							if (ret != 0) {
 | 
				
			||||||
			dev_err(map->dev, "Failed to read IRQ status: %d\n",
 | 
								dev_err(map->dev, "Failed to read IRQ status: %d\n",
 | 
				
			||||||
					ret);
 | 
										ret);
 | 
				
			||||||
 | 
								if (chip->runtime_pm)
 | 
				
			||||||
 | 
									pm_runtime_put(map->dev);
 | 
				
			||||||
			return IRQ_NONE;
 | 
								return IRQ_NONE;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,6 +207,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (chip->runtime_pm)
 | 
				
			||||||
 | 
							pm_runtime_put(map->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (handled)
 | 
						if (handled)
 | 
				
			||||||
		return IRQ_HANDLED;
 | 
							return IRQ_HANDLED;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -285,6 +285,7 @@ struct regmap_irq {
 | 
				
			||||||
 * @ack_base:    Base ack address.  If zero then the chip is clear on read.
 | 
					 * @ack_base:    Base ack address.  If zero then the chip is clear on read.
 | 
				
			||||||
 * @wake_base:   Base address for wake enables.  If zero unsupported.
 | 
					 * @wake_base:   Base address for wake enables.  If zero unsupported.
 | 
				
			||||||
 * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
 | 
					 * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
 | 
				
			||||||
 | 
					 * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @num_regs:    Number of registers in each control bank.
 | 
					 * @num_regs:    Number of registers in each control bank.
 | 
				
			||||||
 * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
 | 
					 * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
 | 
				
			||||||
| 
						 | 
					@ -299,6 +300,7 @@ struct regmap_irq_chip {
 | 
				
			||||||
	unsigned int ack_base;
 | 
						unsigned int ack_base;
 | 
				
			||||||
	unsigned int wake_base;
 | 
						unsigned int wake_base;
 | 
				
			||||||
	unsigned int irq_reg_stride;
 | 
						unsigned int irq_reg_stride;
 | 
				
			||||||
 | 
						bool runtime_pm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int num_regs;
 | 
						int num_regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue