From fcac70930f1a8e48795585234335aef92797e296 Mon Sep 17 00:00:00 2001 From: Xuewen Zhou Date: Thu, 2 Jul 2015 15:50:36 +0800 Subject: [PATCH] regmap: add fast_io_disable_irq property for regmap_config different drivers can share the same regmap handler to access the same hardware module registers by syscon or other mechanism. there will be a synchronization issue if one of the driver access the register in interrupt handler because the spin_lock maybe has been hold by other regsiter access using the same regmap handler and it will cause a dead lock. when fast_io_disable_irq is set to true, the regmap_read/reagmap_write will use spin_lock_irqsave/spin_lockirqrestore to do the syncrhonization to avoid the lock issue. Change-Id: I07424191f3ab65d3f89bfee81fe2b4422cf84e74 Signed-off-by: Xuewen Zhou --- drivers/base/regmap/internal.h | 1 + drivers/base/regmap/regmap.c | 18 +++++++++++++++++- include/linux/regmap.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 5a22bd3..6a66e6b 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -54,6 +54,7 @@ struct regmap { regmap_lock lock; regmap_unlock unlock; void *lock_arg; /* This is passed to lock/unlock functions */ + unsigned long flags; struct device *dev; /* Device we do I/O on */ void *work_buf; /* Scratch buffer used to format I/O */ diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 58cfb32..b9b188e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -297,6 +297,18 @@ static void regmap_unlock_spinlock(void *__map) spin_unlock(&map->spinlock); } +static void regmap_lock_spinlock_irqsave(void *__map) +{ + struct regmap *map = __map; + spin_lock_irqsave(&map->spinlock, map->flags); +} + +static void regmap_unlock_spinlock_irqrestore(void *__map) +{ + struct regmap *map = __map; + spin_unlock_irqrestore(&map->spinlock, map->flags); +} + static void dev_get_regmap_release(struct device *dev, void *res) { /* @@ -403,7 +415,11 @@ struct regmap *regmap_init(struct device *dev, map->unlock = config->unlock; map->lock_arg = config->lock_arg; } else { - if ((bus && bus->fast_io) || + if (config->fast_io_disable_irq) { + spin_lock_init(&map->spinlock); + map->lock = regmap_lock_spinlock_irqsave; + map->unlock = regmap_unlock_spinlock_irqrestore; + } else if ((bus && bus->fast_io) || config->fast_io) { spin_lock_init(&map->spinlock); map->lock = regmap_lock_spinlock; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index bf77dfd..ca3c637 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -193,6 +193,7 @@ struct regmap_config { int (*reg_write)(void *context, unsigned int reg, unsigned int val); bool fast_io; + bool fast_io_disable_irq; unsigned int max_register; const struct regmap_access_table *wr_table; -- 1.9.1