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]
Date:	Fri, 11 Oct 2013 15:31:11 +0100
From:	Anthony Olech <anthony.olech.opensource@...semi.com>
To:	Mark Brown <broonie@...nel.org>,
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>
CC:	LKML <linux-kernel@...r.kernel.org>,
	David Dajun Chen <david.chen@...semi.com>
Subject: [PATCH V1] new API regmap_multi_reg_write() definition

New API regmap_multi_reg_write() is defined that allows a set of reg,val
pairs to be written to a I2C client device as one block transfer from the
point of view of a single I2C master system.

A simple demonstration implementation is included that just splits the
block write request into a sequence of single register writes.

The implementation will be modified later to support those I2C clients
that implement the alternative non-standard MULTIWRITE block write mode
so to achieve a single I2C transfer that will be atomic even in multiple
I2C master systems.

Signed-off-by: Anthony Olech <anthony.olech.opensource@...semi.com>
Signed-off-by: David Dajun Chen <david.chen@...semi.com>
---
This patch is relative to linux-mainline repository tag v3.12-rc4

The Dialog DA9052 family of multifunction power management devices implement
an alternative non-standard I2C MULTIWRITE block write mode that appears on
the I2C bus looking like a normal block write A1-D1-D2-D3-..-Dn, but in fact
the I2C client decodes the bytes as A1-D1-A2-D2-A3-D3-..-An-Dn, where both
the data and addresses are 8 bits wide.

The reason for this unusual mode is to ensure that the set of registers are
recieved atomically, and is crutial in a multi-I2C-master system where the
application processor (a modem chip for example) competes for the I2C bus.

This patch only defines an API that will, after the implementation has been
modified later, support the non-standard I2C MULTIWRITE atomic single I2C
transfer.

The API is also expected to be useful, in single I2C master systems,
for device drivers that need to patch a non-sequential set of registers
in one mutex protected go.

 drivers/base/regmap/regmap.c |   41 +++++++++++++++++++++++++++++++++++++++++
 include/linux/regmap.h       |    2 ++
 2 files changed, 43 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 7d689a1..c42ad69 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1439,6 +1439,47 @@ out:
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_write);
 
+/*
+ * regmap_multi_reg_write(): Write multiple registers to the device
+ *
+ * where the set of register are supplied in any order
+ *
+ * @map: Register map to write to
+ * @regs: Array of structures containing register,value to be written
+ * @num_regs: Number of registers to write
+ *
+ * This function is intended to be used for writing a large block of data
+ * atomically to the device in single transfer for those I2C client devices
+ * that implement this alternative block write mode.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
+				int num_regs)
+{
+	int ret = 0, i;
+
+	for (i = 0; i < num_regs; i++) {
+		int reg = regs[i].reg;
+		if (reg % map->reg_stride)
+			return -EINVAL;
+	}
+
+	map->lock(map->lock_arg);
+
+	for (i = 0; i < num_regs; i++) {
+		ret = _regmap_write(map, regs[i].reg, regs[i].def);
+		if (ret != 0)
+			goto out;
+	}
+out:
+	map->unlock(map->lock_arg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+
 /**
  * regmap_raw_write_async(): Write raw values to one or more registers
  *                           asynchronously
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index a10380b..4b933a3 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -378,6 +378,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 		     const void *val, size_t val_len);
 int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 			size_t val_count);
+int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
+			int num_regs);
 int regmap_raw_write_async(struct regmap *map, unsigned int reg,
 			   const void *val, size_t val_len);
 int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
-- 
end-of-patch for new API regmap_multi_reg_write() definition V1

--
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