lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20150526123921.GA19072@opensource.wolfsonmicro.com>
Date:	Tue, 26 May 2015 13:39:21 +0100
From:	Nariman Poushin <nariman@...nsource.wolfsonmicro.com>
To:	broonie@...nel.org
Cc:	patches@...nsource.wolfsonmicro.com, gregkh@...uxfoundation.org,
	linux-kernel@...r.kernel.org
Subject: [RFC][PATCH] regmap: Add support for sequences of writes with
	specified delays

It is common for devices to require delays after a register write
(clock enables/disables, fll inputs etc, power etc.) as a part of
a larger write sequence from the host side. This interface allows
the called to specify a delay in uS to be applied after each write
in the sequence supplied. This also maintains atomicity for the
sequence, which avoids callers needing this type of behaviour from
having to implement their own locking schemes to achieve this when
also requiring delays within a write sequence

Change-Id:Ie9e77aa48f258b353ffa7406d02e19c28d5f2a44
Signed-off-by: Nariman Poushin <nariman@...nsource.wolfsonmicro.com>
---
 drivers/base/regmap/regmap.c | 59 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/regmap.h       | 20 +++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 58cfb32..ffecc1c 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/rbtree.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/regmap.h>
@@ -1123,6 +1124,30 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
 				 map->format.val_bytes, false);
 }
 
+static int _regmap_sequence_write(struct regmap *map,
+				  const struct reg_sequence *regs,
+				  int num_regs)
+{
+	int i, ret;
+
+	for (i = 0; i < num_regs; i++) {
+		if (regs[i].reg % map->reg_stride)
+			return -EINVAL;
+		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);
+			return ret;
+		}
+
+		if (regs[i].delay_us)
+			udelay(regs[i].delay_us);
+	}
+
+	return 0;
+
+}
+
 static inline void *_regmap_map_get_context(struct regmap *map)
 {
 	return (map->bus) ? map : map->bus_context;
@@ -1564,6 +1589,40 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_read);
 
+/* regmap_sequence_write(): Write multiple registers to the device
+* with an optional delay in microseconds after each write.
+*
+* @map: Register map to write to
+* @regs: Array of structures containing register,value, delay to be written
+* @num_regs: Number of registers to write
+*
+* This function is intended to be used for writing a timed sequence
+* of writes to a device for situations where particular register in
+* an overall sequence requires a post-write delay (common examples of
+* this are clock enables, regulator enables) whilst still maintaining
+* atomic access to the register map (to avoid writes from other threads
+* being interleaved with the current sequence)
+*
+* A value of zero will be returned on success, a negative errno will
+* be returned in error cases.
+*/
+
+int regmap_sequence_write(struct regmap *map,
+			  const struct reg_sequence *regs,
+			  int num_regs)
+{
+	int ret;
+
+	map->lock(map->lock_arg);
+
+	ret = _regmap_sequence_write(map, regs, num_regs);
+
+	map->unlock(map->lock_arg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_sequence_write);
+
 static int _regmap_update_bits(struct regmap *map, unsigned int reg,
 			       unsigned int mask, unsigned int val,
 			       bool *change)
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index bf77dfd..fca76e8 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -45,6 +45,15 @@ struct reg_default {
 	unsigned int def;
 };
 
+/* For use where the host needs to sequence an array of writes with a
+ * delay in microseconds after some (or all) writes.
+ */
+struct reg_sequence {
+	unsigned int reg;
+	unsigned int def;
+	unsigned int delay_us;
+};
+
 #ifdef CONFIG_REGMAP
 
 enum regmap_endian {
@@ -400,6 +409,9 @@ void regcache_mark_dirty(struct regmap *map);
 int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
 			  int num_regs);
 
+int regmap_sequence_write(struct regmap *map, const struct reg_sequence *regs,
+			  int num_regs);
+
 static inline bool regmap_reg_in_range(unsigned int reg,
 				       const struct regmap_range *range)
 {
@@ -595,6 +607,14 @@ static inline struct regmap *dev_get_regmap(struct device *dev,
 	return NULL;
 }
 
+static inline int regmap_sequence_write(struct regmap *map,
+					const struct reg_sequence *regs,
+					int num_regs)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 #endif
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ