[<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 = ®
-
- /* 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