Skip to content

Commit

Permalink
Merge branch 'topic/patch' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/broonie/regmap into regmap-drivers
  • Loading branch information
Mark Brown committed Feb 20, 2012
2 parents 3bf06a1 + 2a14d7d commit aca1e17
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
3 changes: 3 additions & 0 deletions drivers/base/regmap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ struct regmap {
const void *reg_defaults_raw;
void *cache;
bool cache_dirty;

struct reg_default *patch;
int patch_regs;
};

struct regcache_ops {
Expand Down
14 changes: 14 additions & 0 deletions drivers/base/regmap/regcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,22 @@ int regcache_sync(struct regmap *map)
map->cache_ops->name);
name = map->cache_ops->name;
trace_regcache_sync(map->dev, name, "start");

if (!map->cache_dirty)
goto out;

/* Apply any patch first */
map->cache_bypass = 1;
for (i = 0; i < map->patch_regs; i++) {
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
map->patch[i].reg, map->patch[i].def, ret);
goto out;
}
}
map->cache_bypass = 0;

if (map->cache_ops->sync) {
ret = map->cache_ops->sync(map);
} else {
Expand Down
58 changes: 58 additions & 0 deletions drivers/base/regmap/regmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,64 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_update_bits_check);

/**
* regmap_register_patch: Register and apply register updates to be applied
* on device initialistion
*
* @map: Register map to apply updates to.
* @regs: Values to update.
* @num_regs: Number of entries in regs.
*
* Register a set of register updates to be applied to the device
* whenever the device registers are synchronised with the cache and
* apply them immediately. Typically this is used to apply
* corrections to be applied to the device defaults on startup, such
* as the updates some vendors provide to undocumented registers.
*/
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs)
{
int i, ret;
bool bypass;

/* If needed the implementation can be extended to support this */
if (map->patch)
return -EBUSY;

mutex_lock(&map->lock);

bypass = map->cache_bypass;

map->cache_bypass = true;

/* Write out first; it's useful to apply even if we fail later. */
for (i = 0; i < num_regs; i++) {
ret = _regmap_write(map, regs[i].reg, regs[i].def);
if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
regs[i].reg, regs[i].def, ret);
goto out;
}
}

map->patch = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL);
if (map->patch != NULL) {
memcpy(map->patch, regs,
num_regs * sizeof(struct reg_default));
map->patch_regs = num_regs;
} else {
ret = -ENOMEM;
}

out:
map->cache_bypass = bypass;

mutex_unlock(&map->lock);

return ret;
}
EXPORT_SYMBOL_GPL(regmap_register_patch);

static int __init regmap_initcall(void)
{
regmap_debugfs_initcall();
Expand Down
3 changes: 3 additions & 0 deletions include/linux/regmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ void regcache_cache_only(struct regmap *map, bool enable);
void regcache_cache_bypass(struct regmap *map, bool enable);
void regcache_mark_dirty(struct regmap *map);

int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs);

/**
* Description of an IRQ for the generic regmap irq_chip.
*
Expand Down

0 comments on commit aca1e17

Please sign in to comment.