aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/tps65910.c
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2012-02-21 07:51:34 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2012-03-06 12:46:50 -0500
commitdc9913a050f1898c6a77f4f5606bc194d530aafd (patch)
tree777acac138bc643b7eebe9d3b0203ba331e36022 /drivers/mfd/tps65910.c
parent2853378b6eafd8b9e2f0e39ab599c93ce518b04d (diff)
mfd: Use regmap for tps65910 register access.
Using regmap apis for accessing the device registers and using RBTREE caching mechanims for caching registers. Enabling caching of the registers which is used for voltage controls. By doing this, the modify_bits operation is faster as it does not involve the i2c register read from device, just read from cache. This results faster set voltage operation. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/tps65910.c')
-rw-r--r--drivers/mfd/tps65910.c123
1 files changed, 46 insertions, 77 deletions
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 4392f6bca156..1c4f53efee74 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -16,10 +16,12 @@
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/moduleparam.h> 17#include <linux/moduleparam.h>
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/err.h>
19#include <linux/slab.h> 20#include <linux/slab.h>
20#include <linux/i2c.h> 21#include <linux/i2c.h>
21#include <linux/gpio.h> 22#include <linux/gpio.h>
22#include <linux/mfd/core.h> 23#include <linux/mfd/core.h>
24#include <linux/regmap.h>
23#include <linux/mfd/tps65910.h> 25#include <linux/mfd/tps65910.h>
24 26
25static struct mfd_cell tps65910s[] = { 27static struct mfd_cell tps65910s[] = {
@@ -38,99 +40,56 @@ static struct mfd_cell tps65910s[] = {
38static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, 40static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
39 int bytes, void *dest) 41 int bytes, void *dest)
40{ 42{
41 struct i2c_client *i2c = tps65910->i2c_client; 43 return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
42 struct i2c_msg xfer[2];
43 int ret;
44
45 /* Write register */
46 xfer[0].addr = i2c->addr;
47 xfer[0].flags = 0;
48 xfer[0].len = 1;
49 xfer[0].buf = &reg;
50
51 /* Read data */
52 xfer[1].addr = i2c->addr;
53 xfer[1].flags = I2C_M_RD;
54 xfer[1].len = bytes;
55 xfer[1].buf = dest;
56
57 ret = i2c_transfer(i2c->adapter, xfer, 2);
58 if (ret == 2)
59 ret = 0;
60 else if (ret >= 0)
61 ret = -EIO;
62
63 return ret;
64} 44}
65 45
66static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, 46static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
67 int bytes, void *src) 47 int bytes, void *src)
68{ 48{
69 struct i2c_client *i2c = tps65910->i2c_client; 49 return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
70 /* we add 1 byte for device register */
71 u8 msg[TPS65910_MAX_REGISTER + 1];
72 int ret;
73
74 if (bytes > TPS65910_MAX_REGISTER)
75 return -EINVAL;
76
77 msg[0] = reg;
78 memcpy(&msg[1], src, bytes);
79
80 ret = i2c_master_send(i2c, msg, bytes + 1);
81 if (ret < 0)
82 return ret;
83 if (ret != bytes + 1)
84 return -EIO;
85 return 0;
86} 50}
87 51
88int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) 52int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
89{ 53{
90 u8 data; 54 return regmap_update_bits(tps65910->regmap, reg, mask, mask);
91 int err;
92
93 mutex_lock(&tps65910->io_mutex);
94 err = tps65910_i2c_read(tps65910, reg, 1, &data);
95 if (err) {
96 dev_err(tps65910->dev, "read from reg %x failed\n", reg);
97 goto out;
98 }
99
100 data |= mask;
101 err = tps65910_i2c_write(tps65910, reg, 1, &data);
102 if (err)
103 dev_err(tps65910->dev, "write to reg %x failed\n", reg);
104
105out:
106 mutex_unlock(&tps65910->io_mutex);
107 return err;
108} 55}
109EXPORT_SYMBOL_GPL(tps65910_set_bits); 56EXPORT_SYMBOL_GPL(tps65910_set_bits);
110 57
111int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) 58int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
112{ 59{
113 u8 data; 60 return regmap_update_bits(tps65910->regmap, reg, mask, 0);
114 int err;
115
116 mutex_lock(&tps65910->io_mutex);
117 err = tps65910_i2c_read(tps65910, reg, 1, &data);
118 if (err) {
119 dev_err(tps65910->dev, "read from reg %x failed\n", reg);
120 goto out;
121 }
122
123 data &= ~mask;
124 err = tps65910_i2c_write(tps65910, reg, 1, &data);
125 if (err)
126 dev_err(tps65910->dev, "write to reg %x failed\n", reg);
127
128out:
129 mutex_unlock(&tps65910->io_mutex);
130 return err;
131} 61}
132EXPORT_SYMBOL_GPL(tps65910_clear_bits); 62EXPORT_SYMBOL_GPL(tps65910_clear_bits);
133 63
64static bool is_volatile_reg(struct device *dev, unsigned int reg)
65{
66 struct tps65910 *tps65910 = dev_get_drvdata(dev);
67
68 /*
69 * Caching all regulator registers.
70 * All regualator register address range is same for
71 * TPS65910 and TPS65911
72 */
73 if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
74 /* Check for non-existing register */
75 if (tps65910_chip_id(tps65910) == TPS65910)
76 if ((reg == TPS65911_VDDCTRL_OP) ||
77 (reg == TPS65911_VDDCTRL_SR))
78 return true;
79 return false;
80 }
81 return true;
82}
83
84static const struct regmap_config rc5t583_regmap_config = {
85 .reg_bits = 8,
86 .val_bits = 8,
87 .volatile_reg = is_volatile_reg,
88 .max_register = TPS65910_MAX_REGISTER,
89 .num_reg_defaults_raw = TPS65910_MAX_REGISTER,
90 .cache_type = REGCACHE_RBTREE,
91};
92
134static int tps65910_i2c_probe(struct i2c_client *i2c, 93static int tps65910_i2c_probe(struct i2c_client *i2c,
135 const struct i2c_device_id *id) 94 const struct i2c_device_id *id)
136{ 95{
@@ -161,6 +120,13 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
161 tps65910->write = tps65910_i2c_write; 120 tps65910->write = tps65910_i2c_write;
162 mutex_init(&tps65910->io_mutex); 121 mutex_init(&tps65910->io_mutex);
163 122
123 tps65910->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
124 if (IS_ERR(tps65910->regmap)) {
125 ret = PTR_ERR(tps65910->regmap);
126 dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
127 goto regmap_err;
128 }
129
164 ret = mfd_add_devices(tps65910->dev, -1, 130 ret = mfd_add_devices(tps65910->dev, -1,
165 tps65910s, ARRAY_SIZE(tps65910s), 131 tps65910s, ARRAY_SIZE(tps65910s),
166 NULL, 0); 132 NULL, 0);
@@ -178,6 +144,8 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
178 return ret; 144 return ret;
179 145
180err: 146err:
147 regmap_exit(tps65910->regmap);
148regmap_err:
181 kfree(tps65910); 149 kfree(tps65910);
182 kfree(init_data); 150 kfree(init_data);
183 return ret; 151 return ret;
@@ -189,6 +157,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
189 157
190 tps65910_irq_exit(tps65910); 158 tps65910_irq_exit(tps65910);
191 mfd_remove_devices(tps65910->dev); 159 mfd_remove_devices(tps65910->dev);
160 regmap_exit(tps65910->regmap);
192 kfree(tps65910); 161 kfree(tps65910);
193 162
194 return 0; 163 return 0;