kfree(map->selector_work_buf);
}
+++++ ++int regmap_attach_dev(struct device *dev, struct regmap *map,
+++++ ++ const struct regmap_config *config)
+++++ ++{
+++++ ++ struct regmap **m;
+++++ ++
+++++ ++ map->dev = dev;
+++++ ++
+++++ ++ regmap_debugfs_init(map, config->name);
+++++ ++
+++++ ++ /* Add a devres resource for dev_get_regmap() */
+++++ ++ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
+++++ ++ if (!m) {
+++++ ++ regmap_debugfs_exit(map);
+++++ ++ return -ENOMEM;
+++++ ++ }
+++++ ++ *m = map;
+++++ ++ devres_add(dev, m);
+++++ ++
+++++ ++ return 0;
+++++ ++}
+++++ ++EXPORT_SYMBOL_GPL(regmap_attach_dev);
+++++ ++
/**
* regmap_init(): Initialise register map
*
void *bus_context,
const struct regmap_config *config)
{
----- -- struct regmap *map, **m;
+++++ ++ struct regmap *map;
int ret = -EINVAL;
enum regmap_endian reg_endian, val_endian;
int i, j;
else
map->reg_stride = 1;
map->use_single_rw = config->use_single_rw;
+++++++ map->can_multi_write = config->can_multi_write;
map->dev = dev;
map->bus = bus;
map->bus_context = bus_context;
new->window_start = range_cfg->window_start;
new->window_len = range_cfg->window_len;
------- if (_regmap_range_add(map, new) == false) {
+++++++ if (!_regmap_range_add(map, new)) {
dev_err(map->dev, "Failed to add range %d\n", i);
kfree(new);
goto err_range;
}
}
----- -- regmap_debugfs_init(map, config->name);
----- --
ret = regcache_init(map, config);
if (ret != 0)
goto err_range;
----- -- /* Add a devres resource for dev_get_regmap() */
----- -- m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
----- -- if (!m) {
----- -- ret = -ENOMEM;
----- -- goto err_debugfs;
----- -- }
----- -- *m = map;
----- -- devres_add(dev, m);
+++++ ++ if (dev)
+++++ ++ ret = regmap_attach_dev(dev, map, config);
+++++ ++ if (ret != 0)
+++++ ++ goto err_regcache;
return map;
----- --err_debugfs:
----- -- regmap_debugfs_exit(map);
+++++ ++err_regcache:
regcache_exit(map);
err_range:
regmap_range_exit(map);
if (reg % map->reg_stride)
return -EINVAL;
--- ---- map->lock(map->lock_arg);
/*
* Some devices don't support bulk write, for
* them we have a series of single write operations.
*/
if (!map->bus || map->use_single_rw) {
+++ ++++ map->lock(map->lock_arg);
for (i = 0; i < val_count; i++) {
unsigned int ival;
if (ret != 0)
goto out;
}
+++ ++++out:
+++ ++++ map->unlock(map->lock_arg);
} else {
void *wval;
wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
if (!wval) {
--- ---- ret = -ENOMEM;
dev_err(map->dev, "Error in memory allocation\n");
--- ---- goto out;
+++ ++++ return -ENOMEM;
}
for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_inplace(wval + i);
+++ ++++ map->lock(map->lock_arg);
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+++ ++++ map->unlock(map->lock_arg);
kfree(wval);
}
--- ----out:
--- ---- map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);
+++++++ /*
+++++++ * _regmap_raw_multi_reg_write()
+++++++ *
+++++++ * the (register,newvalue) pairs in regs have not been formatted, but
+++++++ * they are all in the same page and have been changed to being page
+++++++ * relative. The page register has been written if that was neccessary.
+++++++ */
+++++++ static int _regmap_raw_multi_reg_write(struct regmap *map,
+++++++ const struct reg_default *regs,
+++++++ size_t num_regs)
+++++++ {
+++++++ int ret;
+++++++ void *buf;
+++++++ int i;
+++++++ u8 *u8;
+++++++ size_t val_bytes = map->format.val_bytes;
+++++++ size_t reg_bytes = map->format.reg_bytes;
+++++++ size_t pad_bytes = map->format.pad_bytes;
+++++++ size_t pair_size = reg_bytes + pad_bytes + val_bytes;
+++++++ size_t len = pair_size * num_regs;
+++++++
+++++++ buf = kzalloc(len, GFP_KERNEL);
+++++++ if (!buf)
+++++++ return -ENOMEM;
+++++++
+++++++ /* We have to linearise by hand. */
+++++++
+++++++ u8 = buf;
+++++++
+++++++ for (i = 0; i < num_regs; i++) {
+++++++ int reg = regs[i].reg;
+++++++ int val = regs[i].def;
+++++++ trace_regmap_hw_write_start(map->dev, reg, 1);
+++++++ map->format.format_reg(u8, reg, map->reg_shift);
+++++++ u8 += reg_bytes + pad_bytes;
+++++++ map->format.format_val(u8, val, 0);
+++++++ u8 += val_bytes;
+++++++ }
+++++++ u8 = buf;
+++++++ *u8 |= map->write_flag_mask;
+++++++
+++++++ ret = map->bus->write(map->bus_context, buf, len);
+++++++
+++++++ kfree(buf);
+++++++
+++++++ for (i = 0; i < num_regs; i++) {
+++++++ int reg = regs[i].reg;
+++++++ trace_regmap_hw_write_done(map->dev, reg, 1);
+++++++ }
+++++++ return ret;
+++++++ }
+++++++
+++++++ static unsigned int _regmap_register_page(struct regmap *map,
+++++++ unsigned int reg,
+++++++ struct regmap_range_node *range)
+++++++ {
+++++++ unsigned int win_page = (reg - range->range_min) / range->window_len;
+++++++
+++++++ return win_page;
+++++++ }
+++++++
+++++++ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
+++++++ struct reg_default *regs,
+++++++ size_t num_regs)
+++++++ {
+++++++ int ret;
+++++++ int i, n;
+++++++ struct reg_default *base;
+++++++ unsigned int this_page;
+++++++ /*
+++++++ * the set of registers are not neccessarily in order, but
+++++++ * since the order of write must be preserved this algorithm
+++++++ * chops the set each time the page changes
+++++++ */
+++++++ base = regs;
+++++++ for (i = 0, n = 0; i < num_regs; i++, n++) {
+++++++ unsigned int reg = regs[i].reg;
+++++++ struct regmap_range_node *range;
+++++++
+++++++ range = _regmap_range_lookup(map, reg);
+++++++ if (range) {
+++++++ unsigned int win_page = _regmap_register_page(map, reg,
+++++++ range);
+++++++
+++++++ if (i == 0)
+++++++ this_page = win_page;
+++++++ if (win_page != this_page) {
+++++++ this_page = win_page;
+++++++ ret = _regmap_raw_multi_reg_write(map, base, n);
+++++++ if (ret != 0)
+++++++ return ret;
+++++++ base += n;
+++++++ n = 0;
+++++++ }
+++++++ ret = _regmap_select_page(map, &base[n].reg, range, 1);
+++++++ if (ret != 0)
+++++++ return ret;
+++++++ }
+++++++ }
+++++++ if (n > 0)
+++++++ return _regmap_raw_multi_reg_write(map, base, n);
+++++++ return 0;
+++++++ }
+++++++
+++++++ static int _regmap_multi_reg_write(struct regmap *map,
+++++++ const struct reg_default *regs,
+++++++ size_t num_regs)
+++++++ {
+++++++ int i;
+++++++ int ret;
+++++++
+++++++ if (!map->can_multi_write) {
+++++++ for (i = 0; i < num_regs; i++) {
+++++++ ret = _regmap_write(map, regs[i].reg, regs[i].def);
+++++++ if (ret != 0)
+++++++ return ret;
+++++++ }
+++++++ return 0;
+++++++ }
+++++++
+++++++ if (!map->format.parse_inplace)
+++++++ return -EINVAL;
+++++++
+++++++ if (map->writeable_reg)
+++++++ for (i = 0; i < num_regs; i++) {
+++++++ int reg = regs[i].reg;
+++++++ if (!map->writeable_reg(map->dev, reg))
+++++++ return -EINVAL;
+++++++ if (reg % map->reg_stride)
+++++++ return -EINVAL;
+++++++ }
+++++++
+++++++ if (!map->cache_bypass) {
+++++++ for (i = 0; i < num_regs; i++) {
+++++++ unsigned int val = regs[i].def;
+++++++ unsigned int reg = regs[i].reg;
+++++++ ret = regcache_write(map, reg, val);
+++++++ if (ret) {
+++++++ dev_err(map->dev,
+++++++ "Error in caching of register: %x ret: %d\n",
+++++++ reg, ret);
+++++++ return ret;
+++++++ }
+++++++ }
+++++++ if (map->cache_only) {
+++++++ map->cache_dirty = true;
+++++++ return 0;
+++++++ }
+++++++ }
+++++++
+++++++ WARN_ON(!map->bus);
+++++++
+++++++ for (i = 0; i < num_regs; i++) {
+++++++ unsigned int reg = regs[i].reg;
+++++++ struct regmap_range_node *range;
+++++++ range = _regmap_range_lookup(map, reg);
+++++++ if (range) {
+++++++ size_t len = sizeof(struct reg_default)*num_regs;
+++++++ struct reg_default *base = kmemdup(regs, len,
+++++++ GFP_KERNEL);
+++++++ if (!base)
+++++++ return -ENOMEM;
+++++++ ret = _regmap_range_multi_paged_reg_write(map, base,
+++++++ num_regs);
+++++++ kfree(base);
+++++++
+++++++ return ret;
+++++++ }
+++++++ }
+++++++ return _regmap_raw_multi_reg_write(map, regs, num_regs);
+++++++ }
+++++++
/*
* regmap_multi_reg_write(): Write multiple registers to the device
*
+++++++ * where the set of register,value pairs are supplied in any order,
+++++++ * possibly not all in a single range.
+++++++ *
+++++++ * @map: Register map to write to
+++++++ * @regs: Array of structures containing register,value to be written
+++++++ * @num_regs: Number of registers to write
+++++++ *
+++++++ * The 'normal' block write mode will send ultimately send data on the
+++++++ * target bus as R,V1,V2,V3,..,Vn where successively higer registers are
+++++++ * addressed. However, this alternative block multi write mode will send
+++++++ * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device
+++++++ * must of course support the mode.
+++++++ *
+++++++ * A value of zero will be returned on success, a negative errno will be
+++++++ * returned in error cases.
+++++++ */
+++++++ int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+++++++ int num_regs)
+++++++ {
+++++++ int ret;
+++++++
+++++++ map->lock(map->lock_arg);
+++++++
+++++++ ret = _regmap_multi_reg_write(map, regs, num_regs);
+++++++
+++++++ map->unlock(map->lock_arg);
+++++++
+++++++ return ret;
+++++++ }
+++++++ EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+++++++
+++++++ /*
+++++++ * regmap_multi_reg_write_bypassed(): Write multiple registers to the
+++++++ * device but not the cache
+++++++ *
* where the set of register are supplied in any order
*
* @map: Register map to write to
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
------- int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
------- int num_regs)
+++++++ int regmap_multi_reg_write_bypassed(struct regmap *map,
+++++++ const struct reg_default *regs,
+++++++ int num_regs)
{
------- int ret = 0, i;
-------
------- for (i = 0; i < num_regs; i++) {
------- int reg = regs[i].reg;
------- if (reg % map->reg_stride)
------- return -EINVAL;
------- }
+++++++ int ret;
+++++++ bool bypass;
map->lock(map->lock_arg);
------- for (i = 0; i < num_regs; i++) {
------- ret = _regmap_write(map, regs[i].reg, regs[i].def);
------- if (ret != 0)
------- goto out;
------- }
------- out:
+++++++ bypass = map->cache_bypass;
+++++++ map->cache_bypass = true;
+++++++
+++++++ ret = _regmap_multi_reg_write(map, regs, num_regs);
+++++++
+++++++ map->cache_bypass = bypass;
+++++++
map->unlock(map->lock_arg);
return ret;
}
------- EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+++++++ EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
/**
* regmap_raw_write_async(): Write raw values to one or more registers
if (map->cache_only)
return -EBUSY;
+++++++ if (!regmap_readable(map, reg))
+++++++ return -EIO;
+++++++
ret = map->reg_read(context, reg, val);
if (ret == 0) {
#ifdef LOG_DEVICE
if (tmp != orig) {
ret = _regmap_write(map, reg, tmp);
------- *change = true;
+++++++ if (change)
+++++++ *change = true;
} else {
------- *change = false;
+++++++ if (change)
+++++++ *change = false;
}
return ret;
int regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
------- bool change;
int ret;
map->lock(map->lock_arg);
------- ret = _regmap_update_bits(map, reg, mask, val, &change);
+++++++ ret = _regmap_update_bits(map, reg, mask, val, NULL);
map->unlock(map->lock_arg);
return ret;
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
------- bool change;
int ret;
map->lock(map->lock_arg);
map->async = true;
------- ret = _regmap_update_bits(map, reg, mask, val, &change);
+++++++ ret = _regmap_update_bits(map, reg, mask, val, NULL);
map->async = false;
* 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.
+++ ++++ *
+++ ++++ * The caller must ensure that this function cannot be called
+++ ++++ * concurrently with either itself or regcache_sync().
*/
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs)
{
struct reg_default *p;
------- int i, ret;
+++++++ int ret;
bool bypass;
if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n",
num_regs))
return 0;
--- --- map->lock(map->lock_arg);
--- ---
--- --- bypass = map->cache_bypass;
--- ---
--- --- map->cache_bypass = true;
--- --- map->async = 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;
--- --- }
--- --- }
--- ---
+ p = krealloc(map->patch,
+ sizeof(struct reg_default) * (map->patch_regs + num_regs),
+ GFP_KERNEL);
+ if (p) {
+ memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
+ map->patch = p;
+ map->patch_regs += num_regs;
+ } else {
--- --- ret = -ENOMEM;
+++ ++++ return -ENOMEM;
+ }
+
+++ +++ map->lock(map->lock_arg);
+++ +++
+++ +++ bypass = map->cache_bypass;
+++ +++
+++ +++ map->cache_bypass = true;
+++ +++ map->async = 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;
- }
- }
+++++++ ret = _regmap_multi_reg_write(map, regs, num_regs);
+++++++ if (ret != 0)
+++++++ goto out;
+++ +++
- p = krealloc(map->patch,
- sizeof(struct reg_default) * (map->patch_regs + num_regs),
- GFP_KERNEL);
- if (p) {
- memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
- map->patch = p;
- map->patch_regs += num_regs;
- } else {
- ret = -ENOMEM;
- }
-
out:
map->async = false;
map->cache_bypass = bypass;
}
EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
++++++ +int regmap_parse_val(struct regmap *map, const void *buf,
++++++ + unsigned int *val)
++++++ +{
++++++ + if (!map->format.parse_val)
++++++ + return -EINVAL;
++++++ +
++++++ + *val = map->format.parse_val(buf);
++++++ +
++++++ + return 0;
++++++ +}
++++++ +EXPORT_SYMBOL_GPL(regmap_parse_val);
++++++ +
static int __init regmap_initcall(void)
{
regmap_debugfs_initcall();