Skip to content

Commit

Permalink
Merge tag 'regmap-patch-initial' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/broonie/regmap into for-3.4

regmap: Inital export of the patching implementation

An initial export of the regmap register patch implementation, mostly
for integration into ASoC so it can be used by drivers there which have
conflicting updates already.
  • Loading branch information
Mark Brown committed Jan 24, 2012
2 parents e8770dd + 22f0d90 commit 55f7f09
Show file tree
Hide file tree
Showing 4 changed files with 75 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
11 changes: 11 additions & 0 deletions drivers/base/regmap/regcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,17 @@ int regcache_sync(struct regmap *map)
map->cache_ops->name);
name = map->cache_ops->name;
trace_regcache_sync(map->dev, name, "start");

/* Apply any patch first */
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;
}
}

if (!map->cache_dirty)
goto out;
if (map->cache_ops->sync) {
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 @@ -669,6 +669,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(sizeof(struct reg_default), num_regs, 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 @@ -149,6 +149,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 55f7f09

Please sign in to comment.