diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-03-24 15:33:59 +0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-03-28 02:18:19 +0400 |
commit | a754a87ce8b17024358c1be8ee0232ef09a7055f (patch) | |
tree | c0d4adee8f490828ca04cd45d6fbb13596d88322 /drivers | |
parent | 70688056a8b4d610249716befe262a74fd123d90 (diff) | |
parent | 22f8d055350066b4a87de4adea8c5213cac54534 (diff) | |
download | linux-a754a87ce8b17024358c1be8ee0232ef09a7055f.tar.xz |
Merge tag 'asoc-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into next/boards
The asoc branch that was already merged into v3.4 contains some
board-level changes that conflict with patches we already have
here, so pull in that branch to resolve the conflicts.
Conflicts:
arch/arm/mach-imx/mach-imx27_visstrim_m10.c
arch/arm/mach-omap2/board-omap4panda.c
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
[olof: Amended fix for mismerge as reported by Kevin Hilman]
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/regmap/internal.h | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 11 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 73 | ||||
-rw-r--r-- | drivers/regulator/core.c | 108 |
4 files changed, 195 insertions, 0 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 1a02b7537c8b..d141b80479b5 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -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 { diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index d1daa5e9fadf..5cd2a37e7688 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -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) { diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 65558034318f..7ac234f0b1c5 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -672,6 +672,79 @@ 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); + +/* + * regmap_get_val_bytes(): Report the size of a register value + * + * Report the size of a register value, mainly intended to for use by + * generic infrastructure built on top of regmap. + */ +int regmap_get_val_bytes(struct regmap *map) +{ + if (map->format.format_write) + return -EINVAL; + + return map->format.val_bytes; +} +EXPORT_SYMBOL_GPL(regmap_get_val_bytes); + static int __init regmap_initcall(void) { regmap_debugfs_initcall(); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e9a83f84adaf..aa5186608aec 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1320,6 +1320,40 @@ struct regulator *regulator_get(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(regulator_get); +static void devm_regulator_release(struct device *dev, void *res) +{ + regulator_put(*(struct regulator **)res); +} + +/** + * devm_regulator_get - Resource managed regulator_get() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get(). Regulators returned from this function are + * automatically regulator_put() on driver detach. See regulator_get() for more + * information. + */ +struct regulator *devm_regulator_get(struct device *dev, const char *id) +{ + struct regulator **ptr, *regulator; + + ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + regulator = regulator_get(dev, id); + if (!IS_ERR(regulator)) { + *ptr = regulator; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return regulator; +} +EXPORT_SYMBOL_GPL(devm_regulator_get); + /** * regulator_get_exclusive - obtain exclusive access to a regulator. * @dev: device for regulator "consumer" @@ -1387,6 +1421,34 @@ void regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_put); +static int devm_regulator_match(struct device *dev, void *res, void *data) +{ + struct regulator **r = res; + if (!r || !*r) { + WARN_ON(!r || !*r); + return 0; + } + return *r == data; +} + +/** + * devm_regulator_put - Resource managed regulator_put() + * @regulator: regulator to free + * + * Deallocate a regulator allocated with devm_regulator_get(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_regulator_put(struct regulator *regulator) +{ + int rc; + + rc = devres_destroy(regulator->dev, devm_regulator_release, + devm_regulator_match, regulator); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_put); + static int _regulator_can_change_status(struct regulator_dev *rdev) { if (!rdev->constraints) @@ -2401,6 +2463,52 @@ err: } EXPORT_SYMBOL_GPL(regulator_bulk_get); +/** + * devm_regulator_bulk_get - managed get multiple regulator consumers + * + * @dev: Device to supply + * @num_consumers: Number of consumers to register + * @consumers: Configuration of consumers; clients are stored here. + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to get several regulator + * consumers in one operation with management, the regulators will + * automatically be freed when the device is unbound. If any of the + * regulators cannot be acquired then any regulators that were + * allocated will be freed before returning to the caller. + */ +int devm_regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + int ret; + + for (i = 0; i < num_consumers; i++) + consumers[i].consumer = NULL; + + for (i = 0; i < num_consumers; i++) { + consumers[i].consumer = devm_regulator_get(dev, + consumers[i].supply); + if (IS_ERR(consumers[i].consumer)) { + ret = PTR_ERR(consumers[i].consumer); + dev_err(dev, "Failed to get supply '%s': %d\n", + consumers[i].supply, ret); + consumers[i].consumer = NULL; + goto err; + } + } + + return 0; + +err: + for (i = 0; i < num_consumers && consumers[i].consumer; i++) + devm_regulator_put(consumers[i].consumer); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); + static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) { struct regulator_bulk_data *bulk = data; |