参照元

説明

引数

返り値

参考

実装

CONFIG_REGMAP 有効: drivers/base/regmap/regmap.c

/*
 * 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 the 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;
	size_t total_size = val_bytes * val_count;

	if (map->bus && !map->format.parse_inplace)
		return -EINVAL;
	if (reg % map->reg_stride)
		return -EINVAL;
	/*
	 * Some devices don't support bulk write, for
	 * them we have a series of single write operations in the first two if
	 * blocks.
	 *
	 * The first if block is used for memory mapped io. It does not allow
	 * val_bytes of 3 for example.
	 * The second one is used for busses which do not have this limitation
	 * and can write arbitrary value lengths.
	 */
	if (!map->bus) {
		map->lock(map->lock_arg);
		for (i = 0; i < val_count; i++) {
			unsigned int ival;

			switch (val_bytes) {
			case 1:
				ival = *(u8 *)(val + (i * val_bytes));
				break;
			case 2:
				ival = *(u16 *)(val + (i * val_bytes));
				break;
			case 4:
				ival = *(u32 *)(val + (i * val_bytes));
				break;
#ifdef CONFIG_64BIT
			case 8:
				ival = *(u64 *)(val + (i * val_bytes));
				break;
#endif
			default:
				ret = -EINVAL;
				goto out;
			}

			ret = _regmap_write(map, reg + (i * map->reg_stride),
					ival);
			if (ret != 0)
				goto out;
		}
out:
		map->unlock(map->lock_arg);
	} else if (map->use_single_write ||
		   (map->max_raw_write && map->max_raw_write < total_size)) {
		int chunk_stride = map->reg_stride;
		size_t chunk_size = val_bytes;
		size_t chunk_count = val_count;

		if (!map->use_single_write) {
			chunk_size = map->max_raw_write;
			if (chunk_size % val_bytes)
				chunk_size -= chunk_size % val_bytes;
			chunk_count = total_size / chunk_size;
			chunk_stride *= chunk_size / val_bytes;
		}

		map->lock(map->lock_arg);
		/* Write as many bytes as possible with chunk_size */
		for (i = 0; i < chunk_count; i++) {
			ret = _regmap_raw_write(map,
						reg + (i * chunk_stride),
						val + (i * chunk_size),
						chunk_size);
			if (ret)
				break;
		}

		/* Write remaining bytes */
		if (!ret && chunk_size * i < total_size) {
			ret = _regmap_raw_write(map, reg + (i * chunk_stride),
						val + (i * chunk_size),
						total_size - i * chunk_size);
		}
		map->unlock(map->lock_arg);
	} else {
		void *wval;

		if (!val_count)
			return -EINVAL;

		wval = kmemdup(val, val_count * val_bytes, map->alloc_flags);
		if (!wval) {
			dev_err(map->dev, "Error in memory allocation\n");
			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);
	}
	return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);

CONFIG_REGMAP 無効: include/linux/regmap.h

static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
				    const void *val, size_t val_count)
{
	WARN_ONCE(1, "regmap API is disabled");
	return -EINVAL;
}

コメント


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-05-10 (木) 11:11:22