Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a458a6d4 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'regmap/topic/core' into regmap-next

parents f7474161 04782ca2
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -139,11 +139,17 @@ struct regmap {
	struct reg_default *patch;
	int patch_regs;

	/* if set, converts bulk rw to single rw */
	bool use_single_rw;
	/* if set, converts bulk read to single read */
	bool use_single_read;
	/* if set, converts bulk read to single read */
	bool use_single_write;
	/* if set, the device supports multi write mode */
	bool can_multi_write;

	/* if set, raw reads/writes are limited to this size */
	size_t max_raw_read;
	size_t max_raw_write;

	struct rb_root range_tree;
	void *selector_work_buf;	/* Scratch buffer used for selector */
};
+1 −1
Original line number Diff line number Diff line
@@ -729,7 +729,7 @@ int regcache_sync_block(struct regmap *map, void *block,
			unsigned int block_base, unsigned int start,
			unsigned int end)
{
	if (regmap_can_raw_write(map) && !map->use_single_rw)
	if (regmap_can_raw_write(map) && !map->use_single_write)
		return regcache_sync_block_raw(map, block, cache_present,
					       block_base, start, end);
	else
+49 −0
Original line number Diff line number Diff line
@@ -209,11 +209,60 @@ static struct regmap_bus regmap_i2c = {
	.val_format_endian_default = REGMAP_ENDIAN_BIG,
};

static int regmap_i2c_smbus_i2c_write(void *context, const void *data,
				      size_t count)
{
	struct device *dev = context;
	struct i2c_client *i2c = to_i2c_client(dev);

	if (count < 1)
		return -EINVAL;
	if (count >= I2C_SMBUS_BLOCK_MAX)
		return -E2BIG;

	--count;
	return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
					      ((u8 *)data + 1));
}

static int regmap_i2c_smbus_i2c_read(void *context, const void *reg,
				     size_t reg_size, void *val,
				     size_t val_size)
{
	struct device *dev = context;
	struct i2c_client *i2c = to_i2c_client(dev);
	int ret;

	if (reg_size != 1 || val_size < 1)
		return -EINVAL;
	if (val_size >= I2C_SMBUS_BLOCK_MAX)
		return -E2BIG;

	ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val);
	if (ret == val_size)
		return 0;
	else if (ret < 0)
		return ret;
	else
		return -EIO;
}

static struct regmap_bus regmap_i2c_smbus_i2c_block = {
	.write = regmap_i2c_smbus_i2c_write,
	.read = regmap_i2c_smbus_i2c_read,
	.max_raw_read = I2C_SMBUS_BLOCK_MAX,
	.max_raw_write = I2C_SMBUS_BLOCK_MAX,
};

static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
					const struct regmap_config *config)
{
	if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
		return &regmap_i2c;
	else if (config->reg_bits == 8 &&
		 i2c_check_functionality(i2c->adapter,
					 I2C_FUNC_SMBUS_I2C_BLOCK))
		return &regmap_i2c_smbus_i2c_block;
	else if (config->val_bits == 16 && config->reg_bits == 8 &&
		 i2c_check_functionality(i2c->adapter,
					 I2C_FUNC_SMBUS_WORD_DATA))
+2 −2
Original line number Diff line number Diff line
@@ -209,7 +209,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
	 * Read in the statuses, using a single bulk read if possible
	 * in order to reduce the I/O overheads.
	 */
	if (!map->use_single_rw && map->reg_stride == 1 &&
	if (!map->use_single_read && map->reg_stride == 1 &&
	    data->irq_reg_stride == 1) {
		u8 *buf8 = data->status_reg_buf;
		u16 *buf16 = data->status_reg_buf;
@@ -398,7 +398,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
	else
		d->irq_reg_stride = 1;

	if (!map->use_single_rw && map->reg_stride == 1 &&
	if (!map->use_single_read && map->reg_stride == 1 &&
	    d->irq_reg_stride == 1) {
		d->status_reg_buf = kmalloc(map->format.val_bytes *
					    chip->num_regs, GFP_KERNEL);
+155 −21
Original line number Diff line number Diff line
@@ -93,6 +93,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)

bool regmap_readable(struct regmap *map, unsigned int reg)
{
	if (!map->reg_read)
		return false;

	if (map->max_register && reg > map->max_register)
		return false;

@@ -573,8 +576,13 @@ struct regmap *regmap_init(struct device *dev,
		map->reg_stride = config->reg_stride;
	else
		map->reg_stride = 1;
	map->use_single_rw = config->use_single_rw;
	map->can_multi_write = config->can_multi_write;
	map->use_single_read = config->use_single_rw || !bus || !bus->read;
	map->use_single_write = config->use_single_rw || !bus || !bus->write;
	map->can_multi_write = config->can_multi_write && bus && bus->write;
	if (bus) {
		map->max_raw_read = bus->max_raw_read;
		map->max_raw_write = bus->max_raw_write;
	}
	map->dev = dev;
	map->bus = bus;
	map->bus_context = bus_context;
@@ -763,7 +771,7 @@ struct regmap *regmap_init(struct device *dev,
		if ((reg_endian != REGMAP_ENDIAN_BIG) ||
		    (val_endian != REGMAP_ENDIAN_BIG))
			goto err_map;
		map->use_single_rw = true;
		map->use_single_write = true;
	}

	if (!map->format.format_write &&
@@ -1382,10 +1390,33 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
 */
bool regmap_can_raw_write(struct regmap *map)
{
	return map->bus && map->format.format_val && map->format.format_reg;
	return map->bus && map->bus->write && map->format.format_val &&
		map->format.format_reg;
}
EXPORT_SYMBOL_GPL(regmap_can_raw_write);

/**
 * regmap_get_raw_read_max - Get the maximum size we can read
 *
 * @map: Map to check.
 */
size_t regmap_get_raw_read_max(struct regmap *map)
{
	return map->max_raw_read;
}
EXPORT_SYMBOL_GPL(regmap_get_raw_read_max);

/**
 * regmap_get_raw_write_max - Get the maximum size we can read
 *
 * @map: Map to check.
 */
size_t regmap_get_raw_write_max(struct regmap *map)
{
	return map->max_raw_write;
}
EXPORT_SYMBOL_GPL(regmap_get_raw_write_max);

static int _regmap_bus_formatted_write(void *context, unsigned int reg,
				       unsigned int val)
{
@@ -1555,6 +1586,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
		return -EINVAL;
	if (val_len % map->format.val_bytes)
		return -EINVAL;
	if (map->max_raw_write && map->max_raw_write > val_len)
		return -E2BIG;

	map->lock(map->lock_arg);

@@ -1669,6 +1702,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
{
	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;
@@ -1677,9 +1711,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,

	/*
	 * Some devices don't support bulk write, for
	 * them we have a series of single write operations.
	 * 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->use_single_rw) {
	if (!map->bus) {
		map->lock(map->lock_arg);
		for (i = 0; i < val_count; i++) {
			unsigned int ival;
@@ -1711,6 +1751,38 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
		}
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;

@@ -1740,7 +1812,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
 *
 * the (register,newvalue) pairs in regs have not been formatted, but
 * they are all in the same page and have been changed to being page
 * relative. The page register has been written if that was neccessary.
 * relative. The page register has been written if that was necessary.
 */
static int _regmap_raw_multi_reg_write(struct regmap *map,
				       const struct reg_default *regs,
@@ -2050,7 +2122,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,

	/*
	 * Some buses or devices flag reads by setting the high bits in the
	 * register addresss; since it's always the high bits for all
	 * register address; 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.
	 */
@@ -2097,8 +2169,6 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
	int ret;
	void *context = _regmap_map_get_context(map);

	WARN_ON(!map->reg_read);

	if (!map->cache_bypass) {
		ret = regcache_read(map, reg, val);
		if (ret == 0)
@@ -2179,6 +2249,8 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
		return -EINVAL;
	if (reg % map->reg_stride)
		return -EINVAL;
	if (val_count == 0)
		return -EINVAL;

	map->lock(map->lock_arg);

@@ -2188,6 +2260,10 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
			ret = -ENOTSUPP;
			goto out;
		}
		if (map->max_raw_read && map->max_raw_read < val_len) {
			ret = -E2BIG;
			goto out;
		}

		/* Physical block read if there's no cache involved */
		ret = _regmap_raw_read(map, reg, val, val_len);
@@ -2297,21 +2373,52 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
		 * 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++) {
		size_t total_size = val_bytes * val_count;

		if (!map->use_single_read &&
		    (!map->max_raw_read || map->max_raw_read > total_size)) {
			ret = regmap_raw_read(map, reg, val,
					      val_bytes * val_count);
			if (ret != 0)
				return ret;
		} else {
			/*
			 * Some devices do not support bulk read or do not
			 * support large bulk reads, for them we have a series
			 * of read operations.
			 */
			int chunk_stride = map->reg_stride;
			size_t chunk_size = val_bytes;
			size_t chunk_count = val_count;

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

			/* Read bytes that fit into a multiple of chunk_size */
			for (i = 0; i < chunk_count; i++) {
				ret = regmap_raw_read(map,
						reg + (i * map->reg_stride),
						val + (i * val_bytes),
						val_bytes);
						      reg + (i * chunk_stride),
						      val + (i * chunk_size),
						      chunk_size);
				if (ret != 0)
					return ret;
			}
		} else {
			ret = regmap_raw_read(map, reg, val,
					      val_bytes * val_count);

			/* Read remaining bytes */
			if (chunk_size * i < total_size) {
				ret = regmap_raw_read(map,
						      reg + (i * chunk_stride),
						      val + (i * chunk_size),
						      total_size - i * chunk_size);
				if (ret != 0)
					return ret;
			}
		}

		for (i = 0; i < val_count * val_bytes; i += val_bytes)
			map->format.parse_inplace(val + i);
@@ -2322,7 +2429,34 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
					  &ival);
			if (ret != 0)
				return ret;

			if (map->format.format_val) {
				map->format.format_val(val + (i * val_bytes), ival, 0);
			} else {
				/* Devices providing read and write
				 * operations can use the bulk I/O
				 * functions if they define a val_bytes,
				 * we assume that the values are native
				 * endian.
				 */
				u32 *u32 = val;
				u16 *u16 = val;
				u8 *u8 = val;

				switch (map->format.val_bytes) {
				case 4:
					u32[i] = ival;
					break;
				case 2:
					u16[i] = ival;
					break;
				case 1:
					u8[i] = ival;
					break;
				default:
					return -EINVAL;
				}
			}
		}
	}

Loading