diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2014-02-05 14:40:26 +0530 |
---|---|---|
committer | Laxman Dewangan <ldewangan@nvidia.com> | 2014-02-05 07:32:14 -0800 |
commit | 2a718abbac2b08cbb6672ccd46559bffff3a930c (patch) | |
tree | fb75b274f74b094c88dbc06bd41643171527a9b6 /drivers/mfd | |
parent | ad1dc56fa44ef4058ca3ea38e6ba3be8ba226cb4 (diff) |
mfd: as3722: provide customized lock to regmap
Add customized locking mechanism for register access
of as3722 device through regmap.
This will help to bypass the locking mechanism when as3722
device get accessed in the atomic context.
Bug 1443347
Change-Id: I43bd44554759387135e1e03741655ebd6472631f
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/363719
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/as3722.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c index 9dc4554292ae..b6365a2e8bba 100644 --- a/drivers/mfd/as3722.c +++ b/drivers/mfd/as3722.c @@ -322,6 +322,29 @@ static const struct regmap_range as3722_writable_ranges[] = { regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG), }; +static void as3722_regmap_config_lock(void *lock) +{ + struct as3722 *as3722 = lock; + + if (as3722->shutdown && (in_atomic() || irqs_disabled())) { + dev_info(as3722->dev, "Xfer without lock\n"); + return; + } + + mutex_lock(&as3722->mutex_config); +} + +static void as3722_regmap_config_unlock(void *lock) +{ + struct as3722 *as3722 = lock; + + if (as3722->shutdown && (in_atomic() || irqs_disabled())) + return; + + mutex_unlock(&as3722->mutex_config); +} + + static const struct regmap_access_table as3722_writable_table = { .yes_ranges = as3722_writable_ranges, .n_yes_ranges = ARRAY_SIZE(as3722_writable_ranges), @@ -337,7 +360,7 @@ static const struct regmap_access_table as3722_volatile_table = { .n_no_ranges = ARRAY_SIZE(as3722_cacheable_ranges), }; -static const struct regmap_config as3722_regmap_config = { +static struct regmap_config as3722_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = AS3722_MAX_REGISTER, @@ -345,6 +368,8 @@ static const struct regmap_config as3722_regmap_config = { .rd_table = &as3722_readable_table, .wr_table = &as3722_writable_table, .volatile_table = &as3722_volatile_table, + .lock = as3722_regmap_config_lock, + .unlock = as3722_regmap_config_unlock, }; static int as3722_i2c_of_probe(struct i2c_client *i2c, @@ -411,6 +436,7 @@ static int as3722_i2c_probe(struct i2c_client *i2c, as3722->dev = &i2c->dev; as3722->chip_irq = i2c->irq; i2c_set_clientdata(i2c, as3722); + as3722->client = i2c; ret = as3722_i2c_non_of_probe(i2c, as3722); if (ret < 0) { @@ -419,7 +445,10 @@ static int as3722_i2c_probe(struct i2c_client *i2c, return ret; } - as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config); + mutex_init(&as3722->mutex_config); + as3722_regmap_config.lock_arg = as3722; + as3722->regmap = devm_regmap_init_i2c(i2c, + (const struct regmap_config *)&as3722_regmap_config); if (IS_ERR(as3722->regmap)) { ret = PTR_ERR(as3722->regmap); dev_err(&i2c->dev, "regmap init failed: %d\n", ret); @@ -477,6 +506,13 @@ static int as3722_i2c_remove(struct i2c_client *i2c) return 0; } +static void as3722_i2c_shutdown(struct i2c_client *i2c) +{ + struct as3722 *as3722 = i2c_get_clientdata(i2c); + + as3722->shutdown = true; +} + static const struct of_device_id as3722_of_match[] = { { .compatible = "ams,as3722", }, {}, @@ -497,6 +533,7 @@ static struct i2c_driver as3722_i2c_driver = { }, .probe = as3722_i2c_probe, .remove = as3722_i2c_remove, + .shutdown = as3722_i2c_shutdown, .id_table = as3722_i2c_id, }; |