Skip to content

Commit

Permalink
regmap: Add support for padding between register and address
Browse files Browse the repository at this point in the history
Some devices, especially those with high speed control interfaces, require
padding between the register and the data. Support this in the regmap API
by providing a pad_bits configuration parameter.

Only devices with integer byte counts are supported.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
  • Loading branch information
Mark Brown committed Jan 20, 2012
1 parent dcd6c92 commit 82159ba
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 11 deletions.
1 change: 1 addition & 0 deletions drivers/base/regmap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct regcache_ops;
struct regmap_format {
size_t buf_size;
size_t reg_bytes;
size_t pad_bytes;
size_t val_bytes;
void (*format_write)(struct regmap *map,
unsigned int reg, unsigned int val);
Expand Down
32 changes: 21 additions & 11 deletions drivers/base/regmap/regmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ struct regmap *regmap_init(struct device *dev,
mutex_init(&map->lock);
map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
map->format.reg_bytes = config->reg_bits / 8;
map->format.pad_bytes = config->pad_bits / 8;
map->format.val_bytes = config->val_bits / 8;
map->format.buf_size += map->format.pad_bytes;
map->dev = dev;
map->bus = bus;
map->max_register = config->max_register;
Expand Down Expand Up @@ -235,7 +237,7 @@ struct regmap *regmap_init(struct device *dev,
!(map->format.format_reg && map->format.format_val))
goto err_map;

map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
if (map->work_buf == NULL) {
ret = -ENOMEM;
goto err_map;
Expand Down Expand Up @@ -329,23 +331,28 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
* send the work_buf directly, otherwise try to do a gather
* write.
*/
if (val == map->work_buf + map->format.reg_bytes)
if (val == (map->work_buf + map->format.pad_bytes +
map->format.reg_bytes))
ret = map->bus->write(map->dev, map->work_buf,
map->format.reg_bytes + val_len);
map->format.reg_bytes +
map->format.pad_bytes +
val_len);
else if (map->bus->gather_write)
ret = map->bus->gather_write(map->dev, map->work_buf,
map->format.reg_bytes,
map->format.reg_bytes +
map->format.pad_bytes,
val, val_len);

/* If that didn't work fall back on linearising by hand. */
if (ret == -ENOTSUPP) {
len = map->format.reg_bytes + val_len;
buf = kmalloc(len, GFP_KERNEL);
len = map->format.reg_bytes + map->format.pad_bytes + val_len;
buf = kzalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;

memcpy(buf, map->work_buf, map->format.reg_bytes);
memcpy(buf + map->format.reg_bytes, val, val_len);
memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
val, val_len);
ret = map->bus->write(map->dev, buf, len);

kfree(buf);
Expand Down Expand Up @@ -387,10 +394,12 @@ int _regmap_write(struct regmap *map, unsigned int reg,

return ret;
} else {
map->format.format_val(map->work_buf + map->format.reg_bytes,
val);
map->format.format_val(map->work_buf + map->format.reg_bytes
+ map->format.pad_bytes, val);
return _regmap_raw_write(map, reg,
map->work_buf + map->format.reg_bytes,
map->work_buf +
map->format.reg_bytes +
map->format.pad_bytes,
map->format.val_bytes);
}
}
Expand Down Expand Up @@ -473,7 +482,8 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
trace_regmap_hw_read_start(map->dev, reg,
val_len / map->format.val_bytes);

ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
ret = map->bus->read(map->dev, map->work_buf,
map->format.reg_bytes + map->format.pad_bytes,
val, val_len);

trace_regmap_hw_read_done(map->dev, reg,
Expand Down
2 changes: 2 additions & 0 deletions include/linux/regmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct reg_default {
* Configuration for the register map of a device.
*
* @reg_bits: Number of bits in a register address, mandatory.
* @pad_bits: Number of bits of padding between register and value.
* @val_bits: Number of bits in a register value, mandatory.
*
* @writeable_reg: Optional callback returning true if the register
Expand Down Expand Up @@ -74,6 +75,7 @@ struct reg_default {
*/
struct regmap_config {
int reg_bits;
int pad_bits;
int val_bits;

bool (*writeable_reg)(struct device *dev, unsigned int reg);
Expand Down

0 comments on commit 82159ba

Please sign in to comment.