diff options
Diffstat (limited to 'drivers/base/regmap')
| -rw-r--r-- | drivers/base/regmap/internal.h | 17 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-irq.c | 57 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 30 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap.c | 344 | 
4 files changed, 411 insertions, 37 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index b986b8660b0..80f9ab9c3aa 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -95,6 +95,9 @@ struct regmap {  	/* if set, converts bulk rw to single rw */  	bool use_single_rw; + +	struct rb_root range_tree; +	void *selector_work_buf;	/* Scratch buffer used for selector */  };  struct regcache_ops { @@ -115,6 +118,20 @@ bool regmap_precious(struct regmap *map, unsigned int reg);  int _regmap_write(struct regmap *map, unsigned int reg,  		  unsigned int val); +struct regmap_range_node { +	struct rb_node node; + +	unsigned int range_min; +	unsigned int range_max; + +	unsigned int selector_reg; +	unsigned int selector_mask; +	int selector_shift; + +	unsigned int window_start; +	unsigned int window_len; +}; +  #ifdef CONFIG_DEBUG_FS  extern void regmap_debugfs_initcall(void);  extern void regmap_debugfs_init(struct regmap *map, const char *name); diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 4fac4b9be88..a89734621e5 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -24,14 +24,18 @@ struct regmap_irq_chip_data {  	struct mutex lock;  	struct regmap *map; -	struct regmap_irq_chip *chip; +	const struct regmap_irq_chip *chip;  	int irq_base;  	struct irq_domain *domain; +	int irq; +	int wake_count; +  	unsigned int *status_buf;  	unsigned int *mask_buf;  	unsigned int *mask_buf_def; +	unsigned int *wake_buf;  	unsigned int irq_reg_stride;  }; @@ -71,6 +75,16 @@ static void regmap_irq_sync_unlock(struct irq_data *data)  				d->chip->mask_base + (i * map->reg_stride));  	} +	/* If we've changed our wakeup count propagate it to the parent */ +	if (d->wake_count < 0) +		for (i = d->wake_count; i < 0; i++) +			irq_set_irq_wake(d->irq, 0); +	else if (d->wake_count > 0) +		for (i = 0; i < d->wake_count; i++) +			irq_set_irq_wake(d->irq, 1); + +	d->wake_count = 0; +  	mutex_unlock(&d->lock);  } @@ -92,18 +106,41 @@ static void regmap_irq_disable(struct irq_data *data)  	d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;  } +static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) +{ +	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); +	struct regmap *map = d->map; +	const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); + +	if (!d->chip->wake_base) +		return -EINVAL; + +	if (on) { +		d->wake_buf[irq_data->reg_offset / map->reg_stride] +			&= ~irq_data->mask; +		d->wake_count++; +	} else { +		d->wake_buf[irq_data->reg_offset / map->reg_stride] +			|= irq_data->mask; +		d->wake_count--; +	} + +	return 0; +} +  static struct irq_chip regmap_irq_chip = {  	.name			= "regmap",  	.irq_bus_lock		= regmap_irq_lock,  	.irq_bus_sync_unlock	= regmap_irq_sync_unlock,  	.irq_disable		= regmap_irq_disable,  	.irq_enable		= regmap_irq_enable, +	.irq_set_wake		= regmap_irq_set_wake,  };  static irqreturn_t regmap_irq_thread(int irq, void *d)  {  	struct regmap_irq_chip_data *data = d; -	struct regmap_irq_chip *chip = data->chip; +	const struct regmap_irq_chip *chip = data->chip;  	struct regmap *map = data->map;  	int ret, i;  	bool handled = false; @@ -195,7 +232,7 @@ static struct irq_domain_ops regmap_domain_ops = {   * register values used by the IRQ controller over suspend and resume.   */  int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, -			int irq_base, struct regmap_irq_chip *chip, +			int irq_base, const struct regmap_irq_chip *chip,  			struct regmap_irq_chip_data **data)  {  	struct regmap_irq_chip_data *d; @@ -240,6 +277,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,  	if (!d->mask_buf_def)  		goto err_alloc; +	if (chip->wake_base) { +		d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, +				      GFP_KERNEL); +		if (!d->wake_buf) +			goto err_alloc; +	} + +	d->irq = irq;  	d->map = map;  	d->chip = chip;  	d->irq_base = irq_base; @@ -294,6 +339,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,  err_domain:  	/* Should really dispose of the domain but... */  err_alloc: +	kfree(d->wake_buf);  	kfree(d->mask_buf_def);  	kfree(d->mask_buf);  	kfree(d->status_buf); @@ -315,6 +361,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)  	free_irq(irq, d);  	/* We should unmap the domain but... */ +	kfree(d->wake_buf);  	kfree(d->mask_buf_def);  	kfree(d->mask_buf);  	kfree(d->status_buf); @@ -346,6 +393,10 @@ EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);   */  int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)  { +	/* Handle holes in the IRQ list */ +	if (!data->chip->irqs[irq].mask) +		return -EINVAL; +  	return irq_create_mapping(data->domain, irq);  }  EXPORT_SYMBOL_GPL(regmap_irq_get_virq); diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index febd6de6c8a..f05fc74dd84 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -37,7 +37,7 @@ static int regmap_mmio_gather_write(void *context,  	BUG_ON(reg_size != 4); -	offset = be32_to_cpup(reg); +	offset = *(u32 *)reg;  	while (val_size) {  		switch (ctx->val_bytes) { @@ -45,14 +45,14 @@ static int regmap_mmio_gather_write(void *context,  			writeb(*(u8 *)val, ctx->regs + offset);  			break;  		case 2: -			writew(be16_to_cpup(val), ctx->regs + offset); +			writew(*(u16 *)val, ctx->regs + offset);  			break;  		case 4: -			writel(be32_to_cpup(val), ctx->regs + offset); +			writel(*(u32 *)val, ctx->regs + offset);  			break;  #ifdef CONFIG_64BIT  		case 8: -			writeq(be64_to_cpup(val), ctx->regs + offset); +			writeq(*(u64 *)val, ctx->regs + offset);  			break;  #endif  		default: @@ -83,7 +83,7 @@ static int regmap_mmio_read(void *context,  	BUG_ON(reg_size != 4); -	offset = be32_to_cpup(reg); +	offset = *(u32 *)reg;  	while (val_size) {  		switch (ctx->val_bytes) { @@ -91,14 +91,14 @@ static int regmap_mmio_read(void *context,  			*(u8 *)val = readb(ctx->regs + offset);  			break;  		case 2: -			*(u16 *)val = cpu_to_be16(readw(ctx->regs + offset)); +			*(u16 *)val = readw(ctx->regs + offset);  			break;  		case 4: -			*(u32 *)val = cpu_to_be32(readl(ctx->regs + offset)); +			*(u32 *)val = readl(ctx->regs + offset);  			break;  #ifdef CONFIG_64BIT  		case 8: -			*(u64 *)val = cpu_to_be32(readq(ctx->regs + offset)); +			*(u64 *)val = readq(ctx->regs + offset);  			break;  #endif  		default: @@ -124,9 +124,11 @@ static struct regmap_bus regmap_mmio = {  	.gather_write = regmap_mmio_gather_write,  	.read = regmap_mmio_read,  	.free_context = regmap_mmio_free_context, +	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE, +	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,  }; -struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, +static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,  					const struct regmap_config *config)  {  	struct regmap_mmio_context *ctx; @@ -162,7 +164,15 @@ struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,  	if (config->reg_stride < min_stride)  		return ERR_PTR(-EINVAL); -	ctx = kzalloc(GFP_KERNEL, sizeof(*ctx)); +	switch (config->reg_format_endian) { +	case REGMAP_ENDIAN_DEFAULT: +	case REGMAP_ENDIAN_NATIVE: +		break; +	default: +		return ERR_PTR(-EINVAL); +	} + +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);  	if (!ctx)  		return ERR_PTR(-ENOMEM); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index c89aa01fb1d..c241ae2f2f1 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -15,12 +15,25 @@  #include <linux/export.h>  #include <linux/mutex.h>  #include <linux/err.h> +#include <linux/rbtree.h>  #define CREATE_TRACE_POINTS  #include <trace/events/regmap.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)  {  	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;  } -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;  	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)  {  	u8 *b = buf; @@ -137,13 +156,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)  	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;  	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)  {  	u8 *b = buf; @@ -151,7 +176,7 @@ static unsigned int regmap_parse_8(void *buf)  	return b[0];  } -static unsigned int regmap_parse_16(void *buf) +static unsigned int regmap_parse_16_be(void *buf)  {  	__be16 *b = buf; @@ -160,6 +185,11 @@ static unsigned int regmap_parse_16(void *buf)  	return b[0];  } +static unsigned int regmap_parse_16_native(void *buf) +{ +	return *(u16 *)buf; +} +  static unsigned int regmap_parse_24(void *buf)  {  	u8 *b = buf; @@ -170,7 +200,7 @@ static unsigned int regmap_parse_24(void *buf)  	return ret;  } -static unsigned int regmap_parse_32(void *buf) +static unsigned int regmap_parse_32_be(void *buf)  {  	__be32 *b = buf; @@ -179,6 +209,11 @@ static unsigned int regmap_parse_32(void *buf)  	return b[0];  } +static unsigned int regmap_parse_32_native(void *buf) +{ +	return *(u32 *)buf; +} +  static void regmap_lock_mutex(struct regmap *map)  {  	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   * @@ -227,6 +323,8 @@ struct regmap *regmap_init(struct device *dev,  {  	struct regmap *map, **m;  	int ret = -EINVAL; +	enum regmap_endian reg_endian, val_endian; +	int i, j;  	if (!bus || !config)  		goto err; @@ -275,6 +373,18 @@ struct regmap *regmap_init(struct device *dev,  		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) {  	case 2:  		switch (config->val_bits) { @@ -321,11 +431,29 @@ struct regmap *regmap_init(struct device *dev,  		break;  	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;  	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;  	default: @@ -338,21 +466,47 @@ struct regmap *regmap_init(struct device *dev,  		map->format.parse_val = regmap_parse_8;  		break;  	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;  	case 24: +		if (val_endian != REGMAP_ENDIAN_BIG) +			goto err_map;  		map->format.format_val = regmap_format_24;  		map->format.parse_val = regmap_parse_24;  		break;  	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;  	} -	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; +	}  	if (!map->format.format_write &&  	    !(map->format.format_reg && map->format.format_val)) @@ -364,27 +518,88 @@ struct regmap *regmap_init(struct device *dev,  		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);  	if (ret < 0) -		goto err_debugfs; +		goto err_range; + +	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) {  		ret = -ENOMEM; -		goto err_cache; +		goto err_debugfs;  	}  	*m = map;  	devres_add(dev, m);  	return map; -err_cache: -	regcache_exit(map);  err_debugfs:  	regmap_debugfs_exit(map); +	regcache_exit(map); +err_range: +	regmap_range_exit(map);  	kfree(map->work_buf);  err_map:  	kfree(map); @@ -481,6 +696,7 @@ void regmap_exit(struct regmap *map)  {  	regcache_exit(map);  	regmap_debugfs_exit(map); +	regmap_range_exit(map);  	if (map->bus->free_context)  		map->bus->free_context(map->bus_context);  	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); +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,  			     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);  	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);  	if (map->format.format_write) { +		ret = _regmap_select_page(map, ®, 1); +		if (ret < 0) +			return ret; +  		map->format.format_write(map, reg, val);  		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;  	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);  	/* @@ -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);  	if (ret == 0) {  		*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);  	} @@ -982,11 +1272,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,  	int ret;  	unsigned int tmp, orig; -	map->lock(map); -  	ret = _regmap_read(map, reg, &orig);  	if (ret != 0) -		goto out; +		return ret;  	tmp = orig & ~mask;  	tmp |= val & mask; @@ -998,9 +1286,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,  		*change = false;  	} -out: -	map->unlock(map); -  	return ret;  } @@ -1018,7 +1303,13 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,  		       unsigned int mask, unsigned int val)  {  	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); @@ -1038,7 +1329,12 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,  			     unsigned int mask, unsigned int val,  			     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);  |