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: <1328697985-22504-1-git-send-email-ldewangan@nvidia.com>
Date:	Wed,  8 Feb 2012 16:16:24 +0530
From:	Laxman Dewangan <ldewangan@...dia.com>
To:	sameo@...ux.intel.com, lrg@...com,
	broonie@...nsource.wolfsonmicro.com, jedu@...mlogic.co.uk,
	gg@...mlogic.co.uk, linux-kernel@...r.kernel.org
Cc:	linux-tegra@...r.kernel.org, ldewangan@...dia.com
Subject: [PATCH V1 1/2] mfd: tps65910: use regmap for device register access.

Using regmap apis for accessing the device register.
using the RBTREE caching mechanims for caching registers.
Also provided apis for enabling register cache from
different sub devices of ts65910.

Signed-off-by: Laxman Dewangan <ldewangan@...dia.com>
---
This patch is towards the performance improvements in the 
voltage change.

 drivers/mfd/Kconfig          |    1 +
 drivers/mfd/tps65910.c       |  136 +++++++++++++++++++-----------------------
 include/linux/mfd/tps65910.h |    3 +
 3 files changed, 65 insertions(+), 75 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index cd13e9f..0e066cd 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -162,6 +162,7 @@ config MFD_TPS65910
 	depends on I2C=y && GPIOLIB
 	select MFD_CORE
 	select GPIO_TPS65910
+	select REGMAP_I2C
 	help
 	  if you say yes here you get support for the TPS65910 series of
 	  Power Management chips.
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 01cf501..1f2b004 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -16,10 +16,12 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/mfd/core.h>
+#include <linux/regmap.h>
 #include <linux/mfd/tps65910.h>
 
 static struct mfd_cell tps65910s[] = {
@@ -34,103 +36,76 @@ static struct mfd_cell tps65910s[] = {
 	},
 };
 
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct tps65910 *tps65910 = dev_get_drvdata(dev);
+	return test_bit(reg, tps65910->cache_reg) ? false : true;
+}
+
+static bool regmap_volatile_range(struct tps65910 *tps65910,
+			unsigned int reg, unsigned int bytes)
+{
+	unsigned int i;
+	for (i = 0; i < bytes; i++)
+		if (!is_volatile_reg(tps65910->dev, reg + i))
+			return false;
+	return true;
+}
 
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
 				  int bytes, void *dest)
 {
-	struct i2c_client *i2c = tps65910->i2c_client;
-	struct i2c_msg xfer[2];
-	int ret;
-
-	/* Write register */
-	xfer[0].addr = i2c->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = i2c->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = bytes;
-	xfer[1].buf = dest;
-
-	ret = i2c_transfer(i2c->adapter, xfer, 2);
-	if (ret == 2)
-		ret = 0;
-	else if (ret >= 0)
-		ret = -EIO;
-
-	return ret;
+	return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
 }
 
 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
-				   int bytes, void *src)
+				  int bytes, void *src)
 {
-	struct i2c_client *i2c = tps65910->i2c_client;
-	/* we add 1 byte for device register */
-	u8 msg[TPS65910_MAX_REGISTER + 1];
+	int i;
 	int ret;
-
-	if (bytes > TPS65910_MAX_REGISTER)
-		return -EINVAL;
-
-	msg[0] = reg;
-	memcpy(&msg[1], src, bytes);
-
-	ret = i2c_master_send(i2c, msg, bytes + 1);
-	if (ret < 0)
-		return ret;
-	if (ret != bytes + 1)
-		return -EIO;
+	unsigned char *wbuf = src;
+	unsigned int ival;
+
+	if (regmap_volatile_range(tps65910, reg, bytes))
+		return regmap_raw_write(tps65910->regmap, reg, src, bytes);
+
+	/* If any of register is non-volatile then use byte-wise transfer */
+	for (i = 0; i < bytes; ++i) {
+		ival = (unsigned int) (*wbuf++);
+		ret = regmap_write(tps65910->regmap, reg, ival);
+		if (ret < 0)
+			return ret;
+	}
 	return 0;
 }
 
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-	u8 data;
-	int err;
-
-	mutex_lock(&tps65910->io_mutex);
-	err = tps65910_i2c_read(tps65910, reg, 1, &data);
-	if (err) {
-		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-		goto out;
-	}
-
-	data |= mask;
-	err = tps65910_i2c_write(tps65910, reg, 1, &data);
-	if (err)
-		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-	mutex_unlock(&tps65910->io_mutex);
-	return err;
+	return regmap_update_bits(tps65910->regmap, reg, mask, mask);
 }
 EXPORT_SYMBOL_GPL(tps65910_set_bits);
 
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-	u8 data;
-	int err;
-
-	mutex_lock(&tps65910->io_mutex);
-	err = tps65910_i2c_read(tps65910, reg, 1, &data);
-	if (err) {
-		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-		goto out;
-	}
-
-	data &= ~mask;
-	err = tps65910_i2c_write(tps65910, reg, 1, &data);
-	if (err)
-		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-	mutex_unlock(&tps65910->io_mutex);
-	return err;
+	return regmap_update_bits(tps65910->regmap, reg, mask, 0);
 }
 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
 
+void tps65910_enable_reg_cache(struct tps65910 *tps65910, int reg)
+{
+	set_bit(reg, tps65910->cache_reg);
+}
+EXPORT_SYMBOL_GPL(tps65910_enable_reg_cache);
+
+static const struct regmap_config rc5t583_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_reg = is_volatile_reg,
+	.max_register = TPS65910_MAX_REGISTER,
+	.num_reg_defaults_raw = TPS65910_MAX_REGISTER,
+	.cache_type = REGCACHE_RBTREE,
+};
+
 static int tps65910_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -161,6 +136,13 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
 	tps65910->write = tps65910_i2c_write;
 	mutex_init(&tps65910->io_mutex);
 
+	tps65910->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+	if (IS_ERR(tps65910->regmap)) {
+		ret = PTR_ERR(tps65910->regmap);
+		dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+		goto regmap_err;
+	}
+
 	ret = mfd_add_devices(tps65910->dev, -1,
 			      tps65910s, ARRAY_SIZE(tps65910s),
 			      NULL, 0);
@@ -178,6 +160,9 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
 	return ret;
 
 err:
+	mfd_remove_devices(tps65910->dev);
+	regmap_exit(tps65910->regmap);
+regmap_err:
 	kfree(tps65910);
 	kfree(init_data);
 	return ret;
@@ -189,6 +174,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
 
 	tps65910_irq_exit(tps65910);
 	mfd_remove_devices(tps65910->dev);
+	regmap_exit(tps65910->regmap);
 	kfree(tps65910);
 
 	return 0;
diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h
index 5c76b96..6c68e2e 100644
--- a/include/linux/mfd/tps65910.h
+++ b/include/linux/mfd/tps65910.h
@@ -805,6 +805,7 @@ struct tps65910_board {
 struct tps65910 {
 	struct device *dev;
 	struct i2c_client *i2c_client;
+	struct regmap *regmap;
 	struct mutex io_mutex;
 	unsigned int id;
 	int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
@@ -824,6 +825,7 @@ struct tps65910 {
 	int irq_base;
 	int irq_num;
 	u32 irq_mask;
+	unsigned long cache_reg[BITS_TO_LONGS(TPS65910_MAX_REGISTER)];
 };
 
 struct tps65910_platform_data {
@@ -837,6 +839,7 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base);
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 		struct tps65910_platform_data *pdata);
 int tps65910_irq_exit(struct tps65910 *tps65910);
+void tps65910_enable_reg_cache(struct tps65910 *tps65910, int reg);
 
 static inline int tps65910_chip_id(struct tps65910 *tps65910)
 {
-- 
1.7.1.1

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