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

Commit 141eba2e authored by Stephen Warren's avatar Stephen Warren Committed by Mark Brown
Browse files

regmap: allow busses to request formatting with specific endianness



Add a field to struct regmap_bus that allows bus drivers to request that
register addresses and values be formatted with a specific endianness.

The default endianness is unchanged from current operation: Big.

Implement native endian formatting/parsing for 16- and 32-bit values.
This will be enough to support regmap-mmio.c.

Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent f8f5701b
Loading
Loading
Loading
Loading
+90 −11
Original line number Diff line number Diff line
@@ -119,13 +119,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 +143,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 +163,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 +172,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 +187,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 +196,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);
@@ -227,6 +249,7 @@ struct regmap *regmap_init(struct device *dev,
{
	struct regmap *map, **m;
	int ret = -EINVAL;
	enum regmap_endian reg_endian, val_endian;

	if (!bus || !config)
		goto err;
@@ -275,6 +298,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 +356,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 +391,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))
+25 −0
Original line number Diff line number Diff line
@@ -43,6 +43,14 @@ struct reg_default {

#ifdef CONFIG_REGMAP

enum regmap_endian {
	/* Unspecified -> 0 -> Backwards compatible default */
	REGMAP_ENDIAN_DEFAULT = 0,
	REGMAP_ENDIAN_BIG,
	REGMAP_ENDIAN_LITTLE,
	REGMAP_ENDIAN_NATIVE,
};

/**
 * Configuration for the register map of a device.
 *
@@ -84,6 +92,12 @@ struct reg_default {
 * @reg_defaults_raw: Power on reset values for registers (for use with
 *                    register cache support).
 * @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
 * @reg_format_endian: Endianness for formatted register addresses. If this is
 *                     DEFAULT, the @reg_format_endian_default value from the
 *                     regmap bus is used.
 * @val_format_endian: Endianness for formatted register values. If this is
 *                     DEFAULT, the @reg_format_endian_default value from the
 *                     regmap bus is used.
 */
struct regmap_config {
	const char *name;
@@ -109,6 +123,9 @@ struct regmap_config {
	u8 write_flag_mask;

	bool use_single_rw;

	enum regmap_endian reg_format_endian;
	enum regmap_endian val_format_endian;
};

typedef int (*regmap_hw_write)(void *context, const void *data,
@@ -133,6 +150,12 @@ typedef void (*regmap_hw_free_context)(void *context);
 *         data.
 * @read_flag_mask: Mask to be set in the top byte of the register when doing
 *                  a read.
 * @reg_format_endian_default: Default endianness for formatted register
 *     addresses. Used when the regmap_config specifies DEFAULT. If this is
 *     DEFAULT, BIG is assumed.
 * @val_format_endian_default: Default endianness for formatted register
 *     values. Used when the regmap_config specifies DEFAULT. If this is
 *     DEFAULT, BIG is assumed.
 */
struct regmap_bus {
	bool fast_io;
@@ -141,6 +164,8 @@ struct regmap_bus {
	regmap_hw_read read;
	regmap_hw_free_context free_context;
	u8 read_flag_mask;
	enum regmap_endian reg_format_endian_default;
	enum regmap_endian val_format_endian_default;
};

struct regmap *regmap_init(struct device *dev,