|
@@ -15,12 +15,25 @@
|
|
#include <linux/export.h>
|
|
#include <linux/export.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/err.h>
|
|
#include <linux/err.h>
|
|
|
|
+#include <linux/rbtree.h>
|
|
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/regmap.h>
|
|
#include <trace/events/regmap.h>
|
|
|
|
|
|
#include "internal.h"
|
|
#include "internal.h"
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Sometimes for failures during very early init the trace
|
|
|
|
+ * infrastructure isn't available early enough to be used. For this
|
|
|
|
+ * sort of problem defining LOG_DEVICE will add printks for basic
|
|
|
|
+ * register I/O on a specific device.
|
|
|
|
+ */
|
|
|
|
+#undef LOG_DEVICE
|
|
|
|
+
|
|
|
|
+static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
|
|
|
+ unsigned int mask, unsigned int val,
|
|
|
|
+ bool *change);
|
|
|
|
+
|
|
bool regmap_writeable(struct regmap *map, unsigned int reg)
|
|
bool regmap_writeable(struct regmap *map, unsigned int reg)
|
|
{
|
|
{
|
|
if (map->max_register && reg > map->max_register)
|
|
if (map->max_register && reg > map->max_register)
|
|
@@ -119,13 +132,19 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
|
|
b[0] = val << shift;
|
|
b[0] = val << shift;
|
|
}
|
|
}
|
|
|
|
|
|
-static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
|
|
|
|
|
|
+static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift)
|
|
{
|
|
{
|
|
__be16 *b = buf;
|
|
__be16 *b = buf;
|
|
|
|
|
|
b[0] = cpu_to_be16(val << shift);
|
|
b[0] = cpu_to_be16(val << shift);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void regmap_format_16_native(void *buf, unsigned int val,
|
|
|
|
+ unsigned int shift)
|
|
|
|
+{
|
|
|
|
+ *(u16 *)buf = val << shift;
|
|
|
|
+}
|
|
|
|
+
|
|
static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
|
|
static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
|
|
{
|
|
{
|
|
u8 *b = buf;
|
|
u8 *b = buf;
|
|
@@ -137,13 +156,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
|
|
b[2] = val;
|
|
b[2] = val;
|
|
}
|
|
}
|
|
|
|
|
|
-static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
|
|
|
|
|
|
+static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift)
|
|
{
|
|
{
|
|
__be32 *b = buf;
|
|
__be32 *b = buf;
|
|
|
|
|
|
b[0] = cpu_to_be32(val << shift);
|
|
b[0] = cpu_to_be32(val << shift);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void regmap_format_32_native(void *buf, unsigned int val,
|
|
|
|
+ unsigned int shift)
|
|
|
|
+{
|
|
|
|
+ *(u32 *)buf = val << shift;
|
|
|
|
+}
|
|
|
|
+
|
|
static unsigned int regmap_parse_8(void *buf)
|
|
static unsigned int regmap_parse_8(void *buf)
|
|
{
|
|
{
|
|
u8 *b = buf;
|
|
u8 *b = buf;
|
|
@@ -151,7 +176,7 @@ static unsigned int regmap_parse_8(void *buf)
|
|
return b[0];
|
|
return b[0];
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned int regmap_parse_16(void *buf)
|
|
|
|
|
|
+static unsigned int regmap_parse_16_be(void *buf)
|
|
{
|
|
{
|
|
__be16 *b = buf;
|
|
__be16 *b = buf;
|
|
|
|
|
|
@@ -160,6 +185,11 @@ static unsigned int regmap_parse_16(void *buf)
|
|
return b[0];
|
|
return b[0];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static unsigned int regmap_parse_16_native(void *buf)
|
|
|
|
+{
|
|
|
|
+ return *(u16 *)buf;
|
|
|
|
+}
|
|
|
|
+
|
|
static unsigned int regmap_parse_24(void *buf)
|
|
static unsigned int regmap_parse_24(void *buf)
|
|
{
|
|
{
|
|
u8 *b = buf;
|
|
u8 *b = buf;
|
|
@@ -170,7 +200,7 @@ static unsigned int regmap_parse_24(void *buf)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned int regmap_parse_32(void *buf)
|
|
|
|
|
|
+static unsigned int regmap_parse_32_be(void *buf)
|
|
{
|
|
{
|
|
__be32 *b = buf;
|
|
__be32 *b = buf;
|
|
|
|
|
|
@@ -179,6 +209,11 @@ static unsigned int regmap_parse_32(void *buf)
|
|
return b[0];
|
|
return b[0];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static unsigned int regmap_parse_32_native(void *buf)
|
|
|
|
+{
|
|
|
|
+ return *(u32 *)buf;
|
|
|
|
+}
|
|
|
|
+
|
|
static void regmap_lock_mutex(struct regmap *map)
|
|
static void regmap_lock_mutex(struct regmap *map)
|
|
{
|
|
{
|
|
mutex_lock(&map->mutex);
|
|
mutex_lock(&map->mutex);
|
|
@@ -208,6 +243,67 @@ static void dev_get_regmap_release(struct device *dev, void *res)
|
|
*/
|
|
*/
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool _regmap_range_add(struct regmap *map,
|
|
|
|
+ struct regmap_range_node *data)
|
|
|
|
+{
|
|
|
|
+ struct rb_root *root = &map->range_tree;
|
|
|
|
+ struct rb_node **new = &(root->rb_node), *parent = NULL;
|
|
|
|
+
|
|
|
|
+ while (*new) {
|
|
|
|
+ struct regmap_range_node *this =
|
|
|
|
+ container_of(*new, struct regmap_range_node, node);
|
|
|
|
+
|
|
|
|
+ parent = *new;
|
|
|
|
+ if (data->range_max < this->range_min)
|
|
|
|
+ new = &((*new)->rb_left);
|
|
|
|
+ else if (data->range_min > this->range_max)
|
|
|
|
+ new = &((*new)->rb_right);
|
|
|
|
+ else
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rb_link_node(&data->node, parent, new);
|
|
|
|
+ rb_insert_color(&data->node, root);
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct regmap_range_node *_regmap_range_lookup(struct regmap *map,
|
|
|
|
+ unsigned int reg)
|
|
|
|
+{
|
|
|
|
+ struct rb_node *node = map->range_tree.rb_node;
|
|
|
|
+
|
|
|
|
+ while (node) {
|
|
|
|
+ struct regmap_range_node *this =
|
|
|
|
+ container_of(node, struct regmap_range_node, node);
|
|
|
|
+
|
|
|
|
+ if (reg < this->range_min)
|
|
|
|
+ node = node->rb_left;
|
|
|
|
+ else if (reg > this->range_max)
|
|
|
|
+ node = node->rb_right;
|
|
|
|
+ else
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void regmap_range_exit(struct regmap *map)
|
|
|
|
+{
|
|
|
|
+ struct rb_node *next;
|
|
|
|
+ struct regmap_range_node *range_node;
|
|
|
|
+
|
|
|
|
+ next = rb_first(&map->range_tree);
|
|
|
|
+ while (next) {
|
|
|
|
+ range_node = rb_entry(next, struct regmap_range_node, node);
|
|
|
|
+ next = rb_next(&range_node->node);
|
|
|
|
+ rb_erase(&range_node->node, &map->range_tree);
|
|
|
|
+ kfree(range_node);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ kfree(map->selector_work_buf);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* regmap_init(): Initialise register map
|
|
* regmap_init(): Initialise register map
|
|
*
|
|
*
|
|
@@ -227,6 +323,8 @@ struct regmap *regmap_init(struct device *dev,
|
|
{
|
|
{
|
|
struct regmap *map, **m;
|
|
struct regmap *map, **m;
|
|
int ret = -EINVAL;
|
|
int ret = -EINVAL;
|
|
|
|
+ enum regmap_endian reg_endian, val_endian;
|
|
|
|
+ int i, j;
|
|
|
|
|
|
if (!bus || !config)
|
|
if (!bus || !config)
|
|
goto err;
|
|
goto err;
|
|
@@ -275,6 +373,18 @@ struct regmap *regmap_init(struct device *dev,
|
|
map->read_flag_mask = bus->read_flag_mask;
|
|
map->read_flag_mask = bus->read_flag_mask;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ reg_endian = config->reg_format_endian;
|
|
|
|
+ if (reg_endian == REGMAP_ENDIAN_DEFAULT)
|
|
|
|
+ reg_endian = bus->reg_format_endian_default;
|
|
|
|
+ if (reg_endian == REGMAP_ENDIAN_DEFAULT)
|
|
|
|
+ reg_endian = REGMAP_ENDIAN_BIG;
|
|
|
|
+
|
|
|
|
+ val_endian = config->val_format_endian;
|
|
|
|
+ if (val_endian == REGMAP_ENDIAN_DEFAULT)
|
|
|
|
+ val_endian = bus->val_format_endian_default;
|
|
|
|
+ if (val_endian == REGMAP_ENDIAN_DEFAULT)
|
|
|
|
+ val_endian = REGMAP_ENDIAN_BIG;
|
|
|
|
+
|
|
switch (config->reg_bits + map->reg_shift) {
|
|
switch (config->reg_bits + map->reg_shift) {
|
|
case 2:
|
|
case 2:
|
|
switch (config->val_bits) {
|
|
switch (config->val_bits) {
|
|
@@ -321,11 +431,29 @@ struct regmap *regmap_init(struct device *dev,
|
|
break;
|
|
break;
|
|
|
|
|
|
case 16:
|
|
case 16:
|
|
- map->format.format_reg = regmap_format_16;
|
|
|
|
|
|
+ switch (reg_endian) {
|
|
|
|
+ case REGMAP_ENDIAN_BIG:
|
|
|
|
+ map->format.format_reg = regmap_format_16_be;
|
|
|
|
+ break;
|
|
|
|
+ case REGMAP_ENDIAN_NATIVE:
|
|
|
|
+ map->format.format_reg = regmap_format_16_native;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ goto err_map;
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
|
|
|
|
case 32:
|
|
case 32:
|
|
- map->format.format_reg = regmap_format_32;
|
|
|
|
|
|
+ switch (reg_endian) {
|
|
|
|
+ case REGMAP_ENDIAN_BIG:
|
|
|
|
+ map->format.format_reg = regmap_format_32_be;
|
|
|
|
+ break;
|
|
|
|
+ case REGMAP_ENDIAN_NATIVE:
|
|
|
|
+ map->format.format_reg = regmap_format_32_native;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ goto err_map;
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
|
|
|
|
default:
|
|
default:
|
|
@@ -338,21 +466,47 @@ struct regmap *regmap_init(struct device *dev,
|
|
map->format.parse_val = regmap_parse_8;
|
|
map->format.parse_val = regmap_parse_8;
|
|
break;
|
|
break;
|
|
case 16:
|
|
case 16:
|
|
- map->format.format_val = regmap_format_16;
|
|
|
|
- map->format.parse_val = regmap_parse_16;
|
|
|
|
|
|
+ switch (val_endian) {
|
|
|
|
+ case REGMAP_ENDIAN_BIG:
|
|
|
|
+ map->format.format_val = regmap_format_16_be;
|
|
|
|
+ map->format.parse_val = regmap_parse_16_be;
|
|
|
|
+ break;
|
|
|
|
+ case REGMAP_ENDIAN_NATIVE:
|
|
|
|
+ map->format.format_val = regmap_format_16_native;
|
|
|
|
+ map->format.parse_val = regmap_parse_16_native;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ goto err_map;
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
case 24:
|
|
case 24:
|
|
|
|
+ if (val_endian != REGMAP_ENDIAN_BIG)
|
|
|
|
+ goto err_map;
|
|
map->format.format_val = regmap_format_24;
|
|
map->format.format_val = regmap_format_24;
|
|
map->format.parse_val = regmap_parse_24;
|
|
map->format.parse_val = regmap_parse_24;
|
|
break;
|
|
break;
|
|
case 32:
|
|
case 32:
|
|
- map->format.format_val = regmap_format_32;
|
|
|
|
- map->format.parse_val = regmap_parse_32;
|
|
|
|
|
|
+ switch (val_endian) {
|
|
|
|
+ case REGMAP_ENDIAN_BIG:
|
|
|
|
+ map->format.format_val = regmap_format_32_be;
|
|
|
|
+ map->format.parse_val = regmap_parse_32_be;
|
|
|
|
+ break;
|
|
|
|
+ case REGMAP_ENDIAN_NATIVE:
|
|
|
|
+ map->format.format_val = regmap_format_32_native;
|
|
|
|
+ map->format.parse_val = regmap_parse_32_native;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ goto err_map;
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- if (map->format.format_write)
|
|
|
|
|
|
+ if (map->format.format_write) {
|
|
|
|
+ if ((reg_endian != REGMAP_ENDIAN_BIG) ||
|
|
|
|
+ (val_endian != REGMAP_ENDIAN_BIG))
|
|
|
|
+ goto err_map;
|
|
map->use_single_rw = true;
|
|
map->use_single_rw = true;
|
|
|
|
+ }
|
|
|
|
|
|
if (!map->format.format_write &&
|
|
if (!map->format.format_write &&
|
|
!(map->format.format_reg && map->format.format_val))
|
|
!(map->format.format_reg && map->format.format_val))
|
|
@@ -364,27 +518,88 @@ struct regmap *regmap_init(struct device *dev,
|
|
goto err_map;
|
|
goto err_map;
|
|
}
|
|
}
|
|
|
|
|
|
- regmap_debugfs_init(map, config->name);
|
|
|
|
|
|
+ map->range_tree = RB_ROOT;
|
|
|
|
+ for (i = 0; i < config->n_ranges; i++) {
|
|
|
|
+ const struct regmap_range_cfg *range_cfg = &config->ranges[i];
|
|
|
|
+ struct regmap_range_node *new;
|
|
|
|
+
|
|
|
|
+ /* Sanity check */
|
|
|
|
+ if (range_cfg->range_max < range_cfg->range_min ||
|
|
|
|
+ range_cfg->range_max > map->max_register ||
|
|
|
|
+ range_cfg->selector_reg > map->max_register ||
|
|
|
|
+ range_cfg->window_len == 0)
|
|
|
|
+ goto err_range;
|
|
|
|
+
|
|
|
|
+ /* Make sure, that this register range has no selector
|
|
|
|
+ or data window within its boundary */
|
|
|
|
+ for (j = 0; j < config->n_ranges; j++) {
|
|
|
|
+ unsigned sel_reg = config->ranges[j].selector_reg;
|
|
|
|
+ unsigned win_min = config->ranges[j].window_start;
|
|
|
|
+ unsigned win_max = win_min +
|
|
|
|
+ config->ranges[j].window_len - 1;
|
|
|
|
+
|
|
|
|
+ if (range_cfg->range_min <= sel_reg &&
|
|
|
|
+ sel_reg <= range_cfg->range_max) {
|
|
|
|
+ goto err_range;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!(win_max < range_cfg->range_min ||
|
|
|
|
+ win_min > range_cfg->range_max)) {
|
|
|
|
+ goto err_range;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
|
|
|
|
+ if (new == NULL) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_range;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ new->range_min = range_cfg->range_min;
|
|
|
|
+ new->range_max = range_cfg->range_max;
|
|
|
|
+ new->selector_reg = range_cfg->selector_reg;
|
|
|
|
+ new->selector_mask = range_cfg->selector_mask;
|
|
|
|
+ new->selector_shift = range_cfg->selector_shift;
|
|
|
|
+ new->window_start = range_cfg->window_start;
|
|
|
|
+ new->window_len = range_cfg->window_len;
|
|
|
|
+
|
|
|
|
+ if (_regmap_range_add(map, new) == false) {
|
|
|
|
+ kfree(new);
|
|
|
|
+ goto err_range;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (map->selector_work_buf == NULL) {
|
|
|
|
+ map->selector_work_buf =
|
|
|
|
+ kzalloc(map->format.buf_size, GFP_KERNEL);
|
|
|
|
+ if (map->selector_work_buf == NULL) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_range;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
ret = regcache_init(map, config);
|
|
ret = regcache_init(map, config);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
- goto err_debugfs;
|
|
|
|
|
|
+ goto err_range;
|
|
|
|
+
|
|
|
|
+ regmap_debugfs_init(map, config->name);
|
|
|
|
|
|
/* Add a devres resource for dev_get_regmap() */
|
|
/* Add a devres resource for dev_get_regmap() */
|
|
m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
|
|
m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
|
|
if (!m) {
|
|
if (!m) {
|
|
ret = -ENOMEM;
|
|
ret = -ENOMEM;
|
|
- goto err_cache;
|
|
|
|
|
|
+ goto err_debugfs;
|
|
}
|
|
}
|
|
*m = map;
|
|
*m = map;
|
|
devres_add(dev, m);
|
|
devres_add(dev, m);
|
|
|
|
|
|
return map;
|
|
return map;
|
|
|
|
|
|
-err_cache:
|
|
|
|
- regcache_exit(map);
|
|
|
|
err_debugfs:
|
|
err_debugfs:
|
|
regmap_debugfs_exit(map);
|
|
regmap_debugfs_exit(map);
|
|
|
|
+ regcache_exit(map);
|
|
|
|
+err_range:
|
|
|
|
+ regmap_range_exit(map);
|
|
kfree(map->work_buf);
|
|
kfree(map->work_buf);
|
|
err_map:
|
|
err_map:
|
|
kfree(map);
|
|
kfree(map);
|
|
@@ -481,6 +696,7 @@ void regmap_exit(struct regmap *map)
|
|
{
|
|
{
|
|
regcache_exit(map);
|
|
regcache_exit(map);
|
|
regmap_debugfs_exit(map);
|
|
regmap_debugfs_exit(map);
|
|
|
|
+ regmap_range_exit(map);
|
|
if (map->bus->free_context)
|
|
if (map->bus->free_context)
|
|
map->bus->free_context(map->bus_context);
|
|
map->bus->free_context(map->bus_context);
|
|
kfree(map->work_buf);
|
|
kfree(map->work_buf);
|
|
@@ -526,6 +742,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_get_regmap);
|
|
EXPORT_SYMBOL_GPL(dev_get_regmap);
|
|
|
|
|
|
|
|
+static int _regmap_select_page(struct regmap *map, unsigned int *reg,
|
|
|
|
+ unsigned int val_num)
|
|
|
|
+{
|
|
|
|
+ struct regmap_range_node *range;
|
|
|
|
+ void *orig_work_buf;
|
|
|
|
+ unsigned int win_offset;
|
|
|
|
+ unsigned int win_page;
|
|
|
|
+ bool page_chg;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ range = _regmap_range_lookup(map, *reg);
|
|
|
|
+ if (range) {
|
|
|
|
+ win_offset = (*reg - range->range_min) % range->window_len;
|
|
|
|
+ win_page = (*reg - range->range_min) / range->window_len;
|
|
|
|
+
|
|
|
|
+ if (val_num > 1) {
|
|
|
|
+ /* Bulk write shouldn't cross range boundary */
|
|
|
|
+ if (*reg + val_num - 1 > range->range_max)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ /* ... or single page boundary */
|
|
|
|
+ if (val_num > range->window_len - win_offset)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* It is possible to have selector register inside data window.
|
|
|
|
+ In that case, selector register is located on every page and
|
|
|
|
+ it needs no page switching, when accessed alone. */
|
|
|
|
+ if (val_num > 1 ||
|
|
|
|
+ range->window_start + win_offset != range->selector_reg) {
|
|
|
|
+ /* Use separate work_buf during page switching */
|
|
|
|
+ orig_work_buf = map->work_buf;
|
|
|
|
+ map->work_buf = map->selector_work_buf;
|
|
|
|
+
|
|
|
|
+ ret = _regmap_update_bits(map, range->selector_reg,
|
|
|
|
+ range->selector_mask,
|
|
|
|
+ win_page << range->selector_shift,
|
|
|
|
+ &page_chg);
|
|
|
|
+
|
|
|
|
+ map->work_buf = orig_work_buf;
|
|
|
|
+
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *reg = range->window_start + win_offset;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|
static int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|
const void *val, size_t val_len)
|
|
const void *val, size_t val_len)
|
|
{
|
|
{
|
|
@@ -563,6 +830,10 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
map->format.format_reg(map->work_buf, reg, map->reg_shift);
|
|
map->format.format_reg(map->work_buf, reg, map->reg_shift);
|
|
|
|
|
|
u8[0] |= map->write_flag_mask;
|
|
u8[0] |= map->write_flag_mask;
|
|
@@ -623,9 +894,18 @@ int _regmap_write(struct regmap *map, unsigned int reg,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef LOG_DEVICE
|
|
|
|
+ if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
|
|
|
|
+ dev_info(map->dev, "%x <= %x\n", reg, val);
|
|
|
|
+#endif
|
|
|
|
+
|
|
trace_regmap_reg_write(map->dev, reg, val);
|
|
trace_regmap_reg_write(map->dev, reg, val);
|
|
|
|
|
|
if (map->format.format_write) {
|
|
if (map->format.format_write) {
|
|
|
|
+ ret = _regmap_select_page(map, ®, 1);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
map->format.format_write(map, reg, val);
|
|
map->format.format_write(map, reg, val);
|
|
|
|
|
|
trace_regmap_hw_write_start(map->dev, reg, 1);
|
|
trace_regmap_hw_write_start(map->dev, reg, 1);
|
|
@@ -783,6 +1063,10 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
|
u8 *u8 = map->work_buf;
|
|
u8 *u8 = map->work_buf;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
+ ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
map->format.format_reg(map->work_buf, reg, map->reg_shift);
|
|
map->format.format_reg(map->work_buf, reg, map->reg_shift);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -826,6 +1110,12 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
|
|
ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
|
|
ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
|
|
if (ret == 0) {
|
|
if (ret == 0) {
|
|
*val = map->format.parse_val(map->work_buf);
|
|
*val = map->format.parse_val(map->work_buf);
|
|
|
|
+
|
|
|
|
+#ifdef LOG_DEVICE
|
|
|
|
+ if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
|
|
|
|
+ dev_info(map->dev, "%x => %x\n", reg, *val);
|
|
|
|
+#endif
|
|
|
|
+
|
|
trace_regmap_reg_read(map->dev, reg, *val);
|
|
trace_regmap_reg_read(map->dev, reg, *val);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -982,11 +1272,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
|
int ret;
|
|
int ret;
|
|
unsigned int tmp, orig;
|
|
unsigned int tmp, orig;
|
|
|
|
|
|
- map->lock(map);
|
|
|
|
-
|
|
|
|
ret = _regmap_read(map, reg, &orig);
|
|
ret = _regmap_read(map, reg, &orig);
|
|
if (ret != 0)
|
|
if (ret != 0)
|
|
- goto out;
|
|
|
|
|
|
+ return ret;
|
|
|
|
|
|
tmp = orig & ~mask;
|
|
tmp = orig & ~mask;
|
|
tmp |= val & mask;
|
|
tmp |= val & mask;
|
|
@@ -998,9 +1286,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
|
*change = false;
|
|
*change = false;
|
|
}
|
|
}
|
|
|
|
|
|
-out:
|
|
|
|
- map->unlock(map);
|
|
|
|
-
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1018,7 +1303,13 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
|
|
unsigned int mask, unsigned int val)
|
|
unsigned int mask, unsigned int val)
|
|
{
|
|
{
|
|
bool change;
|
|
bool change;
|
|
- return _regmap_update_bits(map, reg, mask, val, &change);
|
|
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ map->lock(map);
|
|
|
|
+ ret = _regmap_update_bits(map, reg, mask, val, &change);
|
|
|
|
+ map->unlock(map);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(regmap_update_bits);
|
|
EXPORT_SYMBOL_GPL(regmap_update_bits);
|
|
|
|
|
|
@@ -1038,7 +1329,12 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
|
|
unsigned int mask, unsigned int val,
|
|
unsigned int mask, unsigned int val,
|
|
bool *change)
|
|
bool *change)
|
|
{
|
|
{
|
|
- return _regmap_update_bits(map, reg, mask, val, change);
|
|
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ map->lock(map);
|
|
|
|
+ ret = _regmap_update_bits(map, reg, mask, val, change);
|
|
|
|
+ map->unlock(map);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(regmap_update_bits_check);
|
|
EXPORT_SYMBOL_GPL(regmap_update_bits_check);
|
|
|
|
|