Skip to content
regmap.c 35 KiB
Newer Older
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{
	int ret;

	if (reg % map->reg_stride)
		return -EINVAL;

	map->lock(map->lock_arg);

	ret = _regmap_write(map, reg, val);

	map->unlock(map->lock_arg);

	return ret;
}
EXPORT_SYMBOL_GPL(regmap_write);

/**
 * regmap_raw_write(): Write raw values to one or more registers
 *
 * @map: Register map to write to
 * @reg: Initial register to write to
 * @val: Block of data to be written, laid out for direct transmission to the
 *       device
 * @val_len: Length of data pointed to by val.
 *
 * This function is intended to be used for things like firmware
 * download where a large block of data needs to be transferred to the
 * device.  No formatting will be done on the data provided.
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_raw_write(struct regmap *map, unsigned int reg,
		     const void *val, size_t val_len)
{
	int ret;

	if (val_len % map->format.val_bytes)
		return -EINVAL;
	if (reg % map->reg_stride)
		return -EINVAL;
	map->lock(map->lock_arg);

	ret = _regmap_raw_write(map, reg, val, val_len);

	map->unlock(map->lock_arg);

	return ret;
}
EXPORT_SYMBOL_GPL(regmap_raw_write);

/*
 * regmap_bulk_write(): Write multiple registers to the device
 *
 * @map: Register map to write to
 * @reg: First register to be write from
 * @val: Block of data to be written, in native register size for device
 * @val_count: Number of registers to write
 *
 * This function is intended to be used for writing a large block of
 * data to be device either in single transfer or multiple transfer.
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
		     size_t val_count)
{
	int ret = 0, i;
	size_t val_bytes = map->format.val_bytes;
	void *wval;

	if (!map->format.parse_val)
		return -EINVAL;
	if (reg % map->reg_stride)
		return -EINVAL;
	map->lock(map->lock_arg);

	/* No formatting is require if val_byte is 1 */
	if (val_bytes == 1) {
		wval = (void *)val;
	} else {
		wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
		if (!wval) {
			ret = -ENOMEM;
			dev_err(map->dev, "Error in memory allocation\n");
			goto out;
		}
		for (i = 0; i < val_count * val_bytes; i += val_bytes)
			map->format.parse_val(wval + i);
	}
	/*
	 * Some devices does not support bulk write, for
	 * them we have a series of single write operations.
	 */
	if (map->use_single_rw) {
		for (i = 0; i < val_count; i++) {
			ret = regmap_raw_write(map,
						reg + (i * map->reg_stride),
						val + (i * val_bytes),
						val_bytes);
			if (ret != 0)
				return ret;
		}
	} else {
		ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
	}
	map->unlock(map->lock_arg);
	return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);

static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
			    unsigned int val_len)
{
	struct regmap_range_node *range;
	range = _regmap_range_lookup(map, reg);
	if (range) {
		ret = _regmap_select_page(map, &reg, range,
					  val_len / map->format.val_bytes);
		if (ret != 0)
	map->format.format_reg(map->work_buf, reg, map->reg_shift);
	 * Some buses or devices flag reads by setting the high bits in the
	 * register addresss; since it's always the high bits for all
	 * current formats we can do this here rather than in
	 * formatting.  This may break if we get interesting formats.
	 */
	trace_regmap_hw_read_start(map->dev, reg,
				   val_len / map->format.val_bytes);

	ret = map->bus->read(map->bus_context, map->work_buf,
			     map->format.reg_bytes + map->format.pad_bytes,
Mark Brown's avatar
Mark Brown committed
			     val, val_len);
	trace_regmap_hw_read_done(map->dev, reg,
				  val_len / map->format.val_bytes);

	return ret;
}

static int _regmap_read(struct regmap *map, unsigned int reg,
			unsigned int *val)
{
	int ret;

	if (!map->cache_bypass) {
		ret = regcache_read(map, reg, val);
		if (ret == 0)
			return 0;
	}

	if (map->cache_only)
		return -EBUSY;

	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);
	}
	if (ret == 0 && !map->cache_bypass)
		regcache_write(map, reg, *val);

	return ret;
}

/**
 * regmap_read(): Read a value from a single register
 *
 * @map: Register map to write to
 * @reg: Register to be read from
 * @val: Pointer to store read value
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{
	int ret;

	if (reg % map->reg_stride)
		return -EINVAL;

	map->lock(map->lock_arg);

	ret = _regmap_read(map, reg, val);

	map->unlock(map->lock_arg);

	return ret;
}
EXPORT_SYMBOL_GPL(regmap_read);

/**
 * regmap_raw_read(): Read raw data from the device
 *
 * @map: Register map to write to
 * @reg: First register to be read from
 * @val: Pointer to store read value
 * @val_len: Size of data to read
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
		    size_t val_len)
{
	size_t val_bytes = map->format.val_bytes;
	size_t val_count = val_len / val_bytes;
	unsigned int v;
	int ret, i;
	if (val_len % map->format.val_bytes)
		return -EINVAL;
	if (reg % map->reg_stride)
		return -EINVAL;
	map->lock(map->lock_arg);
	if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
	    map->cache_type == REGCACHE_NONE) {
		/* Physical block read if there's no cache involved */
		ret = _regmap_raw_read(map, reg, val, val_len);

	} else {
		/* Otherwise go word by word for the cache; should be low
		 * cost as we expect to hit the cache.
		 */
		for (i = 0; i < val_count; i++) {
			ret = _regmap_read(map, reg + (i * map->reg_stride),
					   &v);
			map->format.format_val(val + (i * val_bytes), v, 0);
	map->unlock(map->lock_arg);

	return ret;
}
EXPORT_SYMBOL_GPL(regmap_raw_read);

/**
 * regmap_bulk_read(): Read multiple registers from the device
 *
 * @map: Register map to write to
 * @reg: First register to be read from
 * @val: Pointer to store read value, in native register size for device
 * @val_count: Number of registers to read
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
		     size_t val_count)
{
	int ret, i;
	size_t val_bytes = map->format.val_bytes;
	bool vol = regmap_volatile_range(map, reg, val_count);
	if (!map->format.parse_val)
		return -EINVAL;
	if (reg % map->reg_stride)
		return -EINVAL;
	if (vol || map->cache_type == REGCACHE_NONE) {
		/*
		 * Some devices does not support bulk read, for
		 * them we have a series of single read operations.
		 */
		if (map->use_single_rw) {
			for (i = 0; i < val_count; i++) {
				ret = regmap_raw_read(map,
						reg + (i * map->reg_stride),
						val + (i * val_bytes),
						val_bytes);
				if (ret != 0)
					return ret;
			}
		} else {
			ret = regmap_raw_read(map, reg, val,
					      val_bytes * val_count);
			if (ret != 0)
				return ret;
		}

		for (i = 0; i < val_count * val_bytes; i += val_bytes)
			map->format.parse_val(val + i);
	} else {
		for (i = 0; i < val_count; i++) {
			ret = regmap_read(map, reg + (i * map->reg_stride),
			memcpy(val + (i * val_bytes), &ival, val_bytes);

	return 0;
}
EXPORT_SYMBOL_GPL(regmap_bulk_read);

static int _regmap_update_bits(struct regmap *map, unsigned int reg,
			       unsigned int mask, unsigned int val,
			       bool *change)
	unsigned int tmp, orig;
	ret = _regmap_read(map, reg, &orig);
		ret = _regmap_write(map, reg, tmp);
		*change = true;
	} else {
		*change = false;
	}

/**
 * regmap_update_bits: Perform a read/modify/write cycle on the register map
 *
 * @map: Register map to update
 * @reg: Register to update
 * @mask: Bitmask to change
 * @val: New value for bitmask
 *
 * Returns zero for success, a negative number on error.
 */
int regmap_update_bits(struct regmap *map, unsigned int reg,
		       unsigned int mask, unsigned int val)
{
	bool change;
	map->lock(map->lock_arg);
	ret = _regmap_update_bits(map, reg, mask, val, &change);
	map->unlock(map->lock_arg);
EXPORT_SYMBOL_GPL(regmap_update_bits);
/**
 * regmap_update_bits_check: Perform a read/modify/write cycle on the
 *                           register map and report if updated
 *
 * @map: Register map to update
 * @reg: Register to update
 * @mask: Bitmask to change
 * @val: New value for bitmask
 * @change: Boolean indicating if a write was done
 *
 * Returns zero for success, a negative number on error.
 */
int regmap_update_bits_check(struct regmap *map, unsigned int reg,
			     unsigned int mask, unsigned int val,
			     bool *change)
{
	map->lock(map->lock_arg);
	ret = _regmap_update_bits(map, reg, mask, val, change);
	map->unlock(map->lock_arg);
}
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;

	map->lock(map->lock_arg);

	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(num_regs, sizeof(struct reg_default), 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;

	map->unlock(map->lock_arg);

	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();

	return 0;
}
postcore_initcall(regmap_initcall);