All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v1 0/5] regmap: Add a managed API, custom read/write callbacks and support for regmap fields
@ 2019-09-27 13:22 Jean-Jacques Hiblot
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 1/5] regmap: Fix potential overflow in regmap_update_bits() Jean-Jacques Hiblot
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Jean-Jacques Hiblot @ 2019-09-27 13:22 UTC (permalink / raw
  To: u-boot

This is the first of a few series, the goal of which is to facilitate
porting drivers from the linux kernel. Most of the series will be about
adding managed API to existing infrastructure (GPIO, reset, phy,...)

This particular series is about regmaps. It adds the managed API, using
the same API as linux. It also adds support for regmap fields and for
custom read/write callbacks.


Jean-Jacques Hiblot (5):
  regmap: Fix potential overflow in regmap_update_bits()
  regmap: Add devm_regmap_init()
  regmap: Allow providing read/write callbacks through struct
    regmap_config
  regmap: Add support for regmap fields
  test: dm: Add tests for regmap managed API and regmap fields

 arch/sandbox/dts/test.dts |  13 +++
 drivers/core/regmap.c     | 117 ++++++++++++++++++++++-
 include/regmap.h          | 147 +++++++++++++++++++++++++++++
 test/dm/regmap.c          | 189 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 465 insertions(+), 1 deletion(-)

-- 
2.17.1

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 1/5] regmap: Fix potential overflow in regmap_update_bits()
  2019-09-27 13:22 [U-Boot] [PATCH v1 0/5] regmap: Add a managed API, custom read/write callbacks and support for regmap fields Jean-Jacques Hiblot
@ 2019-09-27 13:22 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 2/5] regmap: Add devm_regmap_init() Jean-Jacques Hiblot
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Jean-Jacques Hiblot @ 2019-09-27 13:22 UTC (permalink / raw
  To: u-boot

Mask the value to write so that it cannot affect the bits outside of the
mask

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

 drivers/core/regmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index d1d12eef38..e9e55c9d16 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -462,5 +462,5 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
 
 	reg &= ~mask;
 
-	return regmap_write(map, offset, reg | val);
+	return regmap_write(map, offset, reg | (val & mask));
 }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 2/5] regmap: Add devm_regmap_init()
  2019-09-27 13:22 [U-Boot] [PATCH v1 0/5] regmap: Add a managed API, custom read/write callbacks and support for regmap fields Jean-Jacques Hiblot
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 1/5] regmap: Fix potential overflow in regmap_update_bits() Jean-Jacques Hiblot
@ 2019-09-27 13:22 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 3/5] regmap: Allow providing read/write callbacks through struct regmap_config Jean-Jacques Hiblot
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Jean-Jacques Hiblot @ 2019-09-27 13:22 UTC (permalink / raw
  To: u-boot

Most of new linux drivers are using managed-API to allocate resources. To
ease porting drivers from linux to u-boot, introduce devm_regmap_init() as
a managed API to get a regmap from the device tree.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

 drivers/core/regmap.c | 26 ++++++++++++++++++++++++++
 include/regmap.h      | 19 +++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index e9e55c9d16..f69ff6d12f 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -219,6 +219,32 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
 
 	return 0;
 }
+
+static void devm_regmap_release(struct udevice *dev, void *res)
+{
+	regmap_uninit(*(struct regmap **)res);
+}
+
+struct regmap *devm_regmap_init(struct udevice *dev,
+				const struct regmap_bus *bus,
+				void *bus_context,
+				const struct regmap_config *config)
+{
+	int rc;
+	struct regmap **mapp;
+
+	mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
+			    __GFP_ZERO);
+	if (unlikely(!mapp))
+		return ERR_PTR(-ENOMEM);
+
+	rc = regmap_init_mem(dev_ofnode(dev), mapp);
+	if (rc)
+		return ERR_PTR(rc);
+
+	devres_add(dev, mapp);
+	return *mapp;
+}
 #endif
 
 void *regmap_get_range(struct regmap *map, unsigned int range_num)
diff --git a/include/regmap.h b/include/regmap.h
index 0854200a9c..63a362d86d 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -73,6 +73,9 @@ struct regmap_range {
 	ulong size;
 };
 
+struct regmap_bus;
+struct regmap_config;
+
 /**
  * struct regmap - a way of accessing hardware/bus registers
  *
@@ -332,6 +335,22 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
 
 int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index);
 
+/**
+ * devm_regmap_init() - Initialise register map (device managed)
+ *
+ * @dev: Device that will be interacted with
+ * @bus: Bus-specific callbacks to use with device (IGNORED)
+ * @bus_context: Data passed to bus-specific callbacks (IGNORED)
+ * @config: Configuration for register map (IGNORED)
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ * The structure is automatically freed when the device is unbound
+ */
+struct regmap *devm_regmap_init(struct udevice *dev,
+				const struct regmap_bus *bus,
+				void *bus_context,
+				const struct regmap_config *config);
 /**
  * regmap_get_range() - Obtain the base memory address of a regmap range
  *
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 3/5] regmap: Allow providing read/write callbacks through struct regmap_config
  2019-09-27 13:22 [U-Boot] [PATCH v1 0/5] regmap: Add a managed API, custom read/write callbacks and support for regmap fields Jean-Jacques Hiblot
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 1/5] regmap: Fix potential overflow in regmap_update_bits() Jean-Jacques Hiblot
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 2/5] regmap: Add devm_regmap_init() Jean-Jacques Hiblot
@ 2019-09-27 13:22 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 4/5] regmap: Add support for regmap fields Jean-Jacques Hiblot
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 5/5] test: dm: Add tests for regmap managed API and " Jean-Jacques Hiblot
  4 siblings, 1 reply; 12+ messages in thread
From: Jean-Jacques Hiblot @ 2019-09-27 13:22 UTC (permalink / raw
  To: u-boot

Some linux drivers provide their own read/write functions to access data
from/of the regmap. Adding support for it.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

 drivers/core/regmap.c | 12 ++++++++++++
 include/regmap.h      | 26 +++++++++++++++++++++++---
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index f69ff6d12f..486eea7bd4 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -31,6 +31,9 @@ static struct regmap *regmap_alloc(int count)
 	if (!map)
 		return NULL;
 	map->range_count = count;
+	map->bus_context = NULL;
+	map->reg_read = NULL;
+	map->reg_write = NULL;
 
 	return map;
 }
@@ -241,6 +244,9 @@ struct regmap *devm_regmap_init(struct udevice *dev,
 	rc = regmap_init_mem(dev_ofnode(dev), mapp);
 	if (rc)
 		return ERR_PTR(rc);
+	(*mapp)->reg_read = config->reg_read;
+	(*mapp)->reg_write = config->reg_write;
+	(*mapp)->bus_context = bus_context;
 
 	devres_add(dev, mapp);
 	return *mapp;
@@ -320,6 +326,9 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
 	struct regmap_range *range;
 	void *ptr;
 
+	if (map->reg_read)
+		return map->reg_read(map->bus_context, offset, valp);
+
 	if (range_num >= map->range_count) {
 		debug("%s: range index %d larger than range count\n",
 		      __func__, range_num);
@@ -429,6 +438,9 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
 	struct regmap_range *range;
 	void *ptr;
 
+	if (map->reg_write)
+		return map->reg_write(map->bus_context, offset,
+				      *(unsigned int *)val);
 	if (range_num >= map->range_count) {
 		debug("%s: range index %d larger than range count\n",
 		      __func__, range_num);
diff --git a/include/regmap.h b/include/regmap.h
index 63a362d86d..cc0adf568b 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -74,16 +74,36 @@ struct regmap_range {
 };
 
 struct regmap_bus;
-struct regmap_config;
+/**
+ * struct regmap_config - a way of accessing hardware/bus registers
+ *
+ * @reg_read:	  Optional callback that if filled will be used to perform
+ *		  all the reads from the registers. Should only be provided for
+ *		  devices whose read operation cannot be represented as a simple
+ *		  read operation on a bus such as SPI, I2C, etc. Most of the
+ *		  devices do not need this.
+ * @reg_write:	  Same as above for writing.
+ */
+struct regmap_config {
+	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
+	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+};
 
 /**
  * struct regmap - a way of accessing hardware/bus registers
  *
  * @range_count:	Number of ranges available within the map
  * @ranges:		Array of ranges
+ * @bus_context:	Data passed to bus-specific callbacks
+ * @reg_read:		Optional callback that if filled will be used to perform
+ *			all the reads from the registers.
+ * @reg_write:		Same as above for writing.
  */
 struct regmap {
 	enum regmap_endianness_t endianness;
+	void *bus_context;
+	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
+	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
 	int range_count;
 	struct regmap_range ranges[0];
 };
@@ -340,8 +360,8 @@ int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index);
  *
  * @dev: Device that will be interacted with
  * @bus: Bus-specific callbacks to use with device (IGNORED)
- * @bus_context: Data passed to bus-specific callbacks (IGNORED)
- * @config: Configuration for register map (IGNORED)
+ * @bus_context: Data passed to bus-specific callbacks
+ * @config: Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer to
  * a struct regmap.
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 4/5] regmap: Add support for regmap fields
  2019-09-27 13:22 [U-Boot] [PATCH v1 0/5] regmap: Add a managed API, custom read/write callbacks and support for regmap fields Jean-Jacques Hiblot
                   ` (2 preceding siblings ...)
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 3/5] regmap: Allow providing read/write callbacks through struct regmap_config Jean-Jacques Hiblot
@ 2019-09-27 13:22 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 5/5] test: dm: Add tests for regmap managed API and " Jean-Jacques Hiblot
  4 siblings, 1 reply; 12+ messages in thread
From: Jean-Jacques Hiblot @ 2019-09-27 13:22 UTC (permalink / raw
  To: u-boot

A regmap field is an abstraction available in Linux. It provides to access
bitfields in a regmap without having to worry about shifts and masks.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

 drivers/core/regmap.c |  77 ++++++++++++++++++++++++++++++
 include/regmap.h      | 108 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 185 insertions(+)

diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 486eea7bd4..96ac1db9b0 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -15,6 +15,14 @@
 #include <dm/of_addr.h>
 #include <linux/ioport.h>
 
+struct regmap_field {
+	struct regmap *regmap;
+	unsigned int mask;
+	/* lsb */
+	unsigned int shift;
+	unsigned int reg;
+};
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /**
@@ -502,3 +510,72 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
 
 	return regmap_write(map, offset, reg | (val & mask));
 }
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+	int ret;
+	unsigned int reg_val;
+
+	ret = regmap_read(field->regmap, field->reg, &reg_val);
+	if (ret != 0)
+		return ret;
+
+	reg_val &= field->mask;
+	reg_val >>= field->shift;
+	*val = reg_val;
+
+	return ret;
+}
+
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+	return regmap_update_bits(field->regmap, field->reg, field->mask,
+				  val << field->shift);
+}
+
+static void regmap_field_init(struct regmap_field *rm_field,
+			      struct regmap *regmap,
+			      struct reg_field reg_field)
+{
+	rm_field->regmap = regmap;
+	rm_field->reg = reg_field.reg;
+	rm_field->shift = reg_field.lsb;
+	rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
+}
+
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+					     struct regmap *regmap,
+					     struct reg_field reg_field)
+{
+	struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field),
+						     GFP_KERNEL);
+	if (!rm_field)
+		return ERR_PTR(-ENOMEM);
+
+	regmap_field_init(rm_field, regmap, reg_field);
+
+	return rm_field;
+}
+
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field)
+{
+	devm_kfree(dev, field);
+}
+
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+					struct reg_field reg_field)
+{
+	struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+	if (!rm_field)
+		return ERR_PTR(-ENOMEM);
+
+	regmap_field_init(rm_field, regmap, reg_field);
+
+	return rm_field;
+}
+
+void regmap_field_free(struct regmap_field *field)
+{
+	kfree(field);
+}
diff --git a/include/regmap.h b/include/regmap.h
index cc0adf568b..c1a9c8f548 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -312,6 +312,43 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
 	regmap_read_poll_timeout_test(map, addr, val, cond, sleep_us, \
 				      timeout_ms, 0) \
 
+/**
+ * regmap_field_read_poll_timeout - Poll until a condition is met or a timeout
+ *				    occurs
+ *
+ * @field:	Regmap field to read from
+ * @val:	Unsigned integer variable to read the value into
+ * @cond:	Break condition (usually involving @val)
+ * @sleep_us:	Maximum time to sleep between reads in us (0 tight-loops).
+ * @timeout_ms:	Timeout in ms, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_field_read
+ * error return value in case of a error read. In the two former cases,
+ * the last read value at @addr is stored in @val.
+ *
+ * This is modelled after the regmap_read_poll_timeout macros in linux but
+ * with millisecond timeout.
+ */
+#define regmap_field_read_poll_timeout(field, val, cond, sleep_us, timeout_ms) \
+({ \
+	unsigned long __start = get_timer(0); \
+	int __ret; \
+	for (;;) { \
+		__ret = regmap_field_read((field), &(val)); \
+		if (__ret) \
+			break; \
+		if (cond) \
+			break; \
+		if ((timeout_ms) && get_timer(__start) > (timeout_ms)) { \
+			__ret = regmap_field_read((field), &(val)); \
+			break; \
+		} \
+		if ((sleep_us)) \
+			udelay((sleep_us)); \
+	} \
+	__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
 /**
  * regmap_update_bits() - Perform a read/modify/write using a mask
  *
@@ -388,4 +425,75 @@ void *regmap_get_range(struct regmap *map, unsigned int range_num);
  */
 int regmap_uninit(struct regmap *map);
 
+/**
+ * struct reg_field - Description of an register field
+ *
+ * @reg: Offset of the register within the regmap bank
+ * @lsb: lsb of the register field.
+ * @msb: msb of the register field.
+ * @id_size: port size if it has some ports
+ * @id_offset: address offset for each ports
+ */
+struct reg_field {
+	unsigned int reg;
+	unsigned int lsb;
+	unsigned int msb;
+};
+
+struct regmap_field;
+
+#define REG_FIELD(_reg, _lsb, _msb) {		\
+				.reg = _reg,	\
+				.lsb = _lsb,	\
+				.msb = _msb,	\
+				}
+
+/**
+ * devm_regmap_field_alloc() - Allocate and initialise a register field.
+ *
+ * @dev: Device that will be interacted with
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field will be automatically freed
+ * by the device management code.
+ */
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+					     struct regmap *regmap,
+					     struct reg_field reg_field);
+/**
+ * devm_regmap_field_free() - Free a register field allocated using
+ *                            devm_regmap_field_alloc.
+ *
+ * @dev: Device that will be interacted with
+ * @field: regmap field which should be freed.
+ *
+ * Free register field allocated using devm_regmap_field_alloc(). Usually
+ * drivers need not call this function, as the memory allocated via devm
+ * will be freed as per device-driver life-cyle.
+ */
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field);
+
+/**
+ * regmap_field_write() - Write a value to a regmap field
+ *
+ * @field:	Regmap field to write to
+ * @val:	Data to write to the regmap at the specified offset
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int regmap_field_write(struct regmap_field *field, unsigned int val);
+
+/**
+ * regmap_read() - Read a 32-bit value from a regmap
+ *
+ * @field:	Regmap field to write to
+ * @valp:	Pointer to the buffer to receive the data read from the regmap
+ *		field
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int regmap_field_read(struct regmap_field *field, unsigned int *val);
+
 #endif
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 5/5] test: dm: Add tests for regmap managed API and regmap fields
  2019-09-27 13:22 [U-Boot] [PATCH v1 0/5] regmap: Add a managed API, custom read/write callbacks and support for regmap fields Jean-Jacques Hiblot
                   ` (3 preceding siblings ...)
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 4/5] regmap: Add support for regmap fields Jean-Jacques Hiblot
@ 2019-09-27 13:22 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  4 siblings, 1 reply; 12+ messages in thread
From: Jean-Jacques Hiblot @ 2019-09-27 13:22 UTC (permalink / raw
  To: u-boot

The tests rely on a dummy driver to allocate and initialize the regmap
and the regmap fields using the managed API.
The first test checks that the read/write callbacks are used.
The second test checks if regmap fields behave properly (mask and shift
are ok) by peeking into the regmap.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>

---

 arch/sandbox/dts/test.dts |  13 +++
 test/dm/regmap.c          | 189 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 202 insertions(+)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 27b0baab27..044895586a 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -862,6 +862,19 @@
 	mdio: mdio-test {
 		compatible = "sandbox,mdio";
 	};
+
+	some_regmapped-bus {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+
+		ranges = <0x0 0x0 0x10>;
+		compatible = "simple-bus";
+
+		regmap-test_0 {
+			reg = <0 0x10>;
+			compatible = "sandbox,regmap_test";
+		};
+	};
 };
 
 #include "sandbox_pmic.dtsi"
diff --git a/test/dm/regmap.c b/test/dm/regmap.c
index 82de295cb8..29159ccf41 100644
--- a/test/dm/regmap.c
+++ b/test/dm/regmap.c
@@ -171,3 +171,192 @@ static int dm_test_regmap_poll(struct unit_test_state *uts)
 }
 
 DM_TEST(dm_test_regmap_poll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+struct regmaptest_priv {
+	struct regmap *regmap;
+	struct regmap_field **fields;
+};
+
+#define REGMAP_TEST_BUF_SZ 12
+struct regmaptest_context {
+	unsigned short buffer[REGMAP_TEST_BUF_SZ];
+} ctx;
+
+static int regmaptest_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct regmaptest_context *ctx = context;
+
+	if (reg < ARRAY_SIZE(ctx->buffer)) {
+		ctx->buffer[reg] = val;
+		return 0;
+	}
+	return -ERANGE;
+}
+
+static int regmaptest_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct regmaptest_context *ctx = context;
+
+	if (reg < ARRAY_SIZE(ctx->buffer)) {
+		*val = ctx->buffer[reg];
+		return 0;
+	}
+
+	return -ERANGE;
+}
+
+static struct regmap_config cfg = {
+	.reg_write = regmaptest_write,
+	.reg_read = regmaptest_read,
+};
+
+static const struct reg_field field_cfgs[] = {
+	{
+		.reg = 0,
+		.lsb = 0,
+		.msb = 6,
+	},
+	{
+		.reg = 1,
+		.lsb = 4,
+		.msb = 12,
+	},
+	{
+		.reg = 1,
+		.lsb = 12,
+		.msb = 15,
+	}
+};
+
+static int remaptest_probe(struct udevice *dev)
+{
+	struct regmaptest_priv *priv = dev_get_priv(dev);
+	struct regmap *regmap;
+	struct regmap_field *field;
+	int i;
+	static const int n = ARRAY_SIZE(field_cfgs);
+
+	regmap = devm_regmap_init(dev, NULL, &ctx, &cfg);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+	priv->regmap = regmap;
+
+	priv->fields = devm_kzalloc(dev, sizeof(struct regmap_field *) * n,
+				    GFP_KERNEL);
+	if (!priv->fields)
+		return -ENOMEM;
+
+	for (i = 0 ; i < n; i++) {
+		field = devm_regmap_field_alloc(dev, regmap, field_cfgs[i]);
+		if (IS_ERR(field))
+			return PTR_ERR(field);
+		priv->fields[i] = field;
+	}
+	return 0;
+}
+
+static const struct udevice_id regmaptest_ids[] = {
+	{ .compatible = "sandbox,regmap_test" },
+	{ }
+};
+
+U_BOOT_DRIVER(regmap_test) = {
+	.name	= "regmaptest_drv",
+	.of_match	= regmaptest_ids,
+	.id	= UCLASS_NOP,
+	.probe = remaptest_probe,
+	.priv_auto_alloc_size = sizeof(struct regmaptest_priv),
+};
+
+static int dm_test_devm_regmap(struct unit_test_state *uts)
+{
+	int i = 0;
+	u32 val;
+	u16 pattern[REGMAP_TEST_BUF_SZ];
+	struct udevice *dev;
+	struct regmaptest_priv *priv;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_NOP, "regmap-test_0",
+					      &dev));
+
+	priv = dev_get_priv(dev);
+
+	srand(get_ticks() + rand());
+	for (i = REGMAP_TEST_BUF_SZ - 1; i >= 0; i--) {
+		pattern[i] = rand() & 0xFFFF;
+		ut_assertok(regmap_write(priv->regmap, i, pattern[i]));
+	}
+	for (i = 0; i < REGMAP_TEST_BUF_SZ; i++) {
+		ut_assertok(regmap_read(priv->regmap, i, &val));
+		ut_asserteq(val, ctx.buffer[i]);
+		ut_asserteq(val, pattern[i]);
+	}
+
+	ut_asserteq(-ERANGE, regmap_write(priv->regmap, REGMAP_TEST_BUF_SZ,
+					  val));
+	ut_asserteq(-ERANGE, regmap_read(priv->regmap, REGMAP_TEST_BUF_SZ,
+					 &val));
+	ut_asserteq(-ERANGE, regmap_write(priv->regmap, -1, val));
+	ut_asserteq(-ERANGE, regmap_read(priv->regmap, -1, &val));
+
+	return 0;
+}
+DM_TEST(dm_test_devm_regmap, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int test_one_field(struct unit_test_state *uts,
+			  struct regmap *regmap,
+			  struct regmap_field *field,
+			  struct reg_field field_cfg)
+{
+	int j;
+	unsigned int val;
+	int mask = (1 << (field_cfg.msb - field_cfg.lsb + 1)) - 1;
+	int shift = field_cfg.lsb;
+
+	ut_assertok(regmap_write(regmap, field_cfg.reg, 0));
+	ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+	ut_asserteq(0, val);
+
+	for (j = 0; j <= mask; j++) {
+		ut_assertok(regmap_field_write(field, j));
+		ut_assertok(regmap_field_read(field, &val));
+		ut_asserteq(j, val);
+		ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+		ut_asserteq(j << shift, val);
+	}
+
+	ut_assertok(regmap_field_write(field, mask + 1));
+	ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+	ut_asserteq(0, val);
+
+	ut_assertok(regmap_field_write(field, 0xFFFF));
+	ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+	ut_asserteq(mask << shift, val);
+
+	ut_assertok(regmap_write(regmap, field_cfg.reg, 0xFFFF));
+	ut_assertok(regmap_field_write(field, 0));
+	ut_assertok(regmap_read(regmap, field_cfg.reg, &val));
+	ut_asserteq(0xFFFF & ~(mask << shift), val);
+	return 0;
+}
+
+static int dm_test_devm_regmap_field(struct unit_test_state *uts)
+{
+	int i, rc;
+	struct udevice *dev;
+	struct regmaptest_priv *priv;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_NOP, "regmap-test_0",
+					      &dev));
+	priv = dev_get_priv(dev);
+
+	for (i = 0 ; i < ARRAY_SIZE(field_cfgs); i++) {
+		rc = test_one_field(uts, priv->regmap, priv->fields[i],
+				    field_cfgs[i]);
+		if (rc)
+			break;
+	}
+
+	return 0;
+}
+DM_TEST(dm_test_devm_regmap_field, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 1/5] regmap: Fix potential overflow in regmap_update_bits()
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 1/5] regmap: Fix potential overflow in regmap_update_bits() Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  0 siblings, 0 replies; 12+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw
  To: u-boot

On Fri, 27 Sep 2019 at 07:22, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Mask the value to write so that it cannot affect the bits outside of the
> mask
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  drivers/core/regmap.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

It would be encouraging to see a test updated to catch this problem.

Hmmm actually I just remembered I fixed this - see u-boot-dm/master

Sorry, it looks like your patch was first, but mine does add a test :-)


>
> diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
> index d1d12eef38..e9e55c9d16 100644
> --- a/drivers/core/regmap.c
> +++ b/drivers/core/regmap.c
> @@ -462,5 +462,5 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
>
>         reg &= ~mask;
>
> -       return regmap_write(map, offset, reg | val);
> +       return regmap_write(map, offset, reg | (val & mask));
>  }
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 2/5] regmap: Add devm_regmap_init()
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 2/5] regmap: Add devm_regmap_init() Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  0 siblings, 0 replies; 12+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw
  To: u-boot

Hi Jean-Jacques,

On Fri, 27 Sep 2019 at 07:22, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Most of new linux drivers are using managed-API to allocate resources. To
> ease porting drivers from linux to u-boot, introduce devm_regmap_init() as

U-Boot

Please always spell it that way.

> a managed API to get a regmap from the device tree.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  drivers/core/regmap.c | 26 ++++++++++++++++++++++++++
>  include/regmap.h      | 19 +++++++++++++++++++
>  2 files changed, 45 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

Nit below

>
> diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
> index e9e55c9d16..f69ff6d12f 100644
> --- a/drivers/core/regmap.c
> +++ b/drivers/core/regmap.c
> @@ -219,6 +219,32 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
>
>         return 0;
>  }
> +
> +static void devm_regmap_release(struct udevice *dev, void *res)
> +{
> +       regmap_uninit(*(struct regmap **)res);
> +}
> +
> +struct regmap *devm_regmap_init(struct udevice *dev,
> +                               const struct regmap_bus *bus,
> +                               void *bus_context,
> +                               const struct regmap_config *config)
> +{
> +       int rc;
> +       struct regmap **mapp;
> +
> +       mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
> +                           __GFP_ZERO);
> +       if (unlikely(!mapp))
> +               return ERR_PTR(-ENOMEM);
> +
> +       rc = regmap_init_mem(dev_ofnode(dev), mapp);
> +       if (rc)
> +               return ERR_PTR(rc);
> +
> +       devres_add(dev, mapp);
> +       return *mapp;
> +}
>  #endif
>
>  void *regmap_get_range(struct regmap *map, unsigned int range_num)
> diff --git a/include/regmap.h b/include/regmap.h
> index 0854200a9c..63a362d86d 100644
> --- a/include/regmap.h
> +++ b/include/regmap.h
> @@ -73,6 +73,9 @@ struct regmap_range {
>         ulong size;
>  };
>
> +struct regmap_bus;
> +struct regmap_config;
> +
>  /**
>   * struct regmap - a way of accessing hardware/bus registers
>   *
> @@ -332,6 +335,22 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
>
>  int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index);
>
> +/**
> + * devm_regmap_init() - Initialise register map (device managed)
> + *
> + * @dev: Device that will be interacted with
> + * @bus: Bus-specific callbacks to use with device (IGNORED)
> + * @bus_context: Data passed to bus-specific callbacks (IGNORED)
> + * @config: Configuration for register map (IGNORED)
> + *

@return


> + * The return value will be an ERR_PTR() on error or a valid pointer to
> + * a struct regmap.
> + * The structure is automatically freed when the device is unbound
> + */
> +struct regmap *devm_regmap_init(struct udevice *dev,
> +                               const struct regmap_bus *bus,
> +                               void *bus_context,
> +                               const struct regmap_config *config);
>  /**
>   * regmap_get_range() - Obtain the base memory address of a regmap range
>   *
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 3/5] regmap: Allow providing read/write callbacks through struct regmap_config
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 3/5] regmap: Allow providing read/write callbacks through struct regmap_config Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  2019-11-04 16:07     ` Jean-Jacques Hiblot
  0 siblings, 1 reply; 12+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw
  To: u-boot

Hi Jean-Jacques,

On Fri, 27 Sep 2019 at 07:22, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Some linux drivers provide their own read/write functions to access data
> from/of the regmap. Adding support for it.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  drivers/core/regmap.c | 12 ++++++++++++
>  include/regmap.h      | 26 +++++++++++++++++++++++---
>  2 files changed, 35 insertions(+), 3 deletions(-)

This increases code size in SPL so should probably be controlled by a Kconfig.

Also I wonder if regmap should become a uclass if we are adding
operations to it?

Regards,
Simon

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 4/5] regmap: Add support for regmap fields
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 4/5] regmap: Add support for regmap fields Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  0 siblings, 0 replies; 12+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw
  To: u-boot

On Fri, 27 Sep 2019 at 07:22, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> A regmap field is an abstraction available in Linux. It provides to access
> bitfields in a regmap without having to worry about shifts and masks.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  drivers/core/regmap.c |  77 ++++++++++++++++++++++++++++++
>  include/regmap.h      | 108 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 185 insertions(+)
>

Reviewed-by: Simon Glass <sjg@chromium.org>

But this does need tests.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 5/5] test: dm: Add tests for regmap managed API and regmap fields
  2019-09-27 13:22 ` [U-Boot] [PATCH v1 5/5] test: dm: Add tests for regmap managed API and " Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  0 siblings, 0 replies; 12+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw
  To: u-boot

On Fri, 27 Sep 2019 at 07:22, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> The tests rely on a dummy driver to allocate and initialize the regmap
> and the regmap fields using the managed API.
> The first test checks that the read/write callbacks are used.
> The second test checks if regmap fields behave properly (mask and shift
> are ok) by peeking into the regmap.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>
> ---
>
>  arch/sandbox/dts/test.dts |  13 +++
>  test/dm/regmap.c          | 189 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 202 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [U-Boot] [PATCH v1 3/5] regmap: Allow providing read/write callbacks through struct regmap_config
  2019-10-30  1:48   ` Simon Glass
@ 2019-11-04 16:07     ` Jean-Jacques Hiblot
  0 siblings, 0 replies; 12+ messages in thread
From: Jean-Jacques Hiblot @ 2019-11-04 16:07 UTC (permalink / raw
  To: u-boot


On 30/10/2019 02:48, Simon Glass wrote:
> Hi Jean-Jacques,
>
> On Fri, 27 Sep 2019 at 07:22, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>> Some linux drivers provide their own read/write functions to access data
>> from/of the regmap. Adding support for it.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>> ---
>>
>>   drivers/core/regmap.c | 12 ++++++++++++
>>   include/regmap.h      | 26 +++++++++++++++++++++++---
>>   2 files changed, 35 insertions(+), 3 deletions(-)
> This increases code size in SPL so should probably be controlled by a Kconfig.
OK.
>
> Also I wonder if regmap should become a uclass if we are adding

I don't see a real value in making a regmap a device. IMO It will just 
make things more complex than needed.

JJ

> operations to it?
>
> Regards,
> Simon
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2019-11-04 16:07 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-09-27 13:22 [U-Boot] [PATCH v1 0/5] regmap: Add a managed API, custom read/write callbacks and support for regmap fields Jean-Jacques Hiblot
2019-09-27 13:22 ` [U-Boot] [PATCH v1 1/5] regmap: Fix potential overflow in regmap_update_bits() Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass
2019-09-27 13:22 ` [U-Boot] [PATCH v1 2/5] regmap: Add devm_regmap_init() Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass
2019-09-27 13:22 ` [U-Boot] [PATCH v1 3/5] regmap: Allow providing read/write callbacks through struct regmap_config Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass
2019-11-04 16:07     ` Jean-Jacques Hiblot
2019-09-27 13:22 ` [U-Boot] [PATCH v1 4/5] regmap: Add support for regmap fields Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass
2019-09-27 13:22 ` [U-Boot] [PATCH v1 5/5] test: dm: Add tests for regmap managed API and " Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.