aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/88pm860x-i2c.c
diff options
context:
space:
mode:
authorJett.Zhou <jtzhou@marvell.com>2011-11-11 02:38:26 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2012-01-08 18:37:30 -0500
commit5bdf7411bc2329cfe015ba6dcf59531e0c6891b8 (patch)
treede63284df29fb92001b4f75b1827c6b00920bbec /drivers/mfd/88pm860x-i2c.c
parent289aabdaf943f3676a16908e2c3cc1a1f9877ccb (diff)
mfd: Fix 88pm860x test bank i2c interface bug
There are two banks in 88pm8607. One is the normal bank, and the other one is the test bank, it means it have the same register address in the normal bank and test bank seperately. For test bank register, it needs a special I2C sequence to acess as below, Touching to 0xFA address Touching to 0xFB address Touching to 0xFF address Accessing bank register Touching to 0xFE address Touching to 0xFC address This sequence can't be interrupted. It means that we can't use i2c_transfef() to implement touching 0xFA address. Otherwise, other i2c operation may be inserted into 0xFA and 0xFB operation since the lock of i2c_adapter is already released. So for test bank we implemented specific i2c read/write operation; Signed-off-by: Jett.Zhou <jtzhou@marvell.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/88pm860x-i2c.c')
-rw-r--r--drivers/mfd/88pm860x-i2c.c135
1 files changed, 89 insertions, 46 deletions
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index e017dc88622a..f629d6f4e3e9 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -126,23 +126,69 @@ out:
126} 126}
127EXPORT_SYMBOL(pm860x_set_bits); 127EXPORT_SYMBOL(pm860x_set_bits);
128 128
129static int read_device(struct i2c_client *i2c, int reg,
130 int bytes, void *dest)
131{
132 unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
133 unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
134 struct i2c_adapter *adap = i2c->adapter;
135 struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0},
136 {i2c->addr, I2C_M_RD, 0, msgbuf1},
137 };
138 int num = 1, ret = 0;
139
140 if (dest == NULL)
141 return -EINVAL;
142 msgbuf0[0] = (unsigned char)reg; /* command */
143 msg[1].len = bytes;
144
145 /* if data needs to read back, num should be 2 */
146 if (bytes > 0)
147 num = 2;
148 ret = adap->algo->master_xfer(adap, msg, num);
149 memcpy(dest, msgbuf1, bytes);
150 if (ret < 0)
151 return ret;
152 return 0;
153}
154
155static int write_device(struct i2c_client *i2c, int reg,
156 int bytes, void *src)
157{
158 unsigned char buf[bytes + 1];
159 struct i2c_adapter *adap = i2c->adapter;
160 struct i2c_msg msg;
161 int ret;
162
163 buf[0] = (unsigned char)reg;
164 memcpy(&buf[1], src, bytes);
165 msg.addr = i2c->addr;
166 msg.flags = 0;
167 msg.len = bytes + 1;
168 msg.buf = buf;
169
170 ret = adap->algo->master_xfer(adap, &msg, 1);
171 if (ret < 0)
172 return ret;
173 return 0;
174}
175
129int pm860x_page_reg_read(struct i2c_client *i2c, int reg) 176int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
130{ 177{
131 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
132 unsigned char zero = 0; 178 unsigned char zero = 0;
133 unsigned char data; 179 unsigned char data;
134 int ret; 180 int ret;
135 181
136 mutex_lock(&chip->io_lock); 182 i2c_lock_adapter(i2c->adapter);
137 pm860x_write_device(i2c, 0xFA, 0, &zero); 183 read_device(i2c, 0xFA, 0, &zero);
138 pm860x_write_device(i2c, 0xFB, 0, &zero); 184 read_device(i2c, 0xFB, 0, &zero);
139 pm860x_write_device(i2c, 0xFF, 0, &zero); 185 read_device(i2c, 0xFF, 0, &zero);
140 ret = pm860x_read_device(i2c, reg, 1, &data); 186 ret = read_device(i2c, reg, 1, &data);
141 if (ret >= 0) 187 if (ret >= 0)
142 ret = (int)data; 188 ret = (int)data;
143 pm860x_write_device(i2c, 0xFE, 0, &zero); 189 read_device(i2c, 0xFE, 0, &zero);
144 pm860x_write_device(i2c, 0xFC, 0, &zero); 190 read_device(i2c, 0xFC, 0, &zero);
145 mutex_unlock(&chip->io_lock); 191 i2c_unlock_adapter(i2c->adapter);
146 return ret; 192 return ret;
147} 193}
148EXPORT_SYMBOL(pm860x_page_reg_read); 194EXPORT_SYMBOL(pm860x_page_reg_read);
@@ -150,18 +196,17 @@ EXPORT_SYMBOL(pm860x_page_reg_read);
150int pm860x_page_reg_write(struct i2c_client *i2c, int reg, 196int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
151 unsigned char data) 197 unsigned char data)
152{ 198{
153 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
154 unsigned char zero; 199 unsigned char zero;
155 int ret; 200 int ret;
156 201
157 mutex_lock(&chip->io_lock); 202 i2c_lock_adapter(i2c->adapter);
158 pm860x_write_device(i2c, 0xFA, 0, &zero); 203 read_device(i2c, 0xFA, 0, &zero);
159 pm860x_write_device(i2c, 0xFB, 0, &zero); 204 read_device(i2c, 0xFB, 0, &zero);
160 pm860x_write_device(i2c, 0xFF, 0, &zero); 205 read_device(i2c, 0xFF, 0, &zero);
161 ret = pm860x_write_device(i2c, reg, 1, &data); 206 ret = write_device(i2c, reg, 1, &data);
162 pm860x_write_device(i2c, 0xFE, 0, &zero); 207 read_device(i2c, 0xFE, 0, &zero);
163 pm860x_write_device(i2c, 0xFC, 0, &zero); 208 read_device(i2c, 0xFC, 0, &zero);
164 mutex_unlock(&chip->io_lock); 209 i2c_unlock_adapter(i2c->adapter);
165 return ret; 210 return ret;
166} 211}
167EXPORT_SYMBOL(pm860x_page_reg_write); 212EXPORT_SYMBOL(pm860x_page_reg_write);
@@ -169,18 +214,17 @@ EXPORT_SYMBOL(pm860x_page_reg_write);
169int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, 214int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
170 int count, unsigned char *buf) 215 int count, unsigned char *buf)
171{ 216{
172 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
173 unsigned char zero = 0; 217 unsigned char zero = 0;
174 int ret; 218 int ret;
175 219
176 mutex_lock(&chip->io_lock); 220 i2c_lock_adapter(i2c->adapter);
177 pm860x_write_device(i2c, 0xFA, 0, &zero); 221 read_device(i2c, 0xfa, 0, &zero);
178 pm860x_write_device(i2c, 0xFB, 0, &zero); 222 read_device(i2c, 0xfb, 0, &zero);
179 pm860x_write_device(i2c, 0xFF, 0, &zero); 223 read_device(i2c, 0xff, 0, &zero);
180 ret = pm860x_read_device(i2c, reg, count, buf); 224 ret = read_device(i2c, reg, count, buf);
181 pm860x_write_device(i2c, 0xFE, 0, &zero); 225 read_device(i2c, 0xFE, 0, &zero);
182 pm860x_write_device(i2c, 0xFC, 0, &zero); 226 read_device(i2c, 0xFC, 0, &zero);
183 mutex_unlock(&chip->io_lock); 227 i2c_unlock_adapter(i2c->adapter);
184 return ret; 228 return ret;
185} 229}
186EXPORT_SYMBOL(pm860x_page_bulk_read); 230EXPORT_SYMBOL(pm860x_page_bulk_read);
@@ -188,18 +232,18 @@ EXPORT_SYMBOL(pm860x_page_bulk_read);
188int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, 232int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
189 int count, unsigned char *buf) 233 int count, unsigned char *buf)
190{ 234{
191 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
192 unsigned char zero = 0; 235 unsigned char zero = 0;
193 int ret; 236 int ret;
194 237
195 mutex_lock(&chip->io_lock); 238 i2c_lock_adapter(i2c->adapter);
196 pm860x_write_device(i2c, 0xFA, 0, &zero); 239 read_device(i2c, 0xFA, 0, &zero);
197 pm860x_write_device(i2c, 0xFB, 0, &zero); 240 read_device(i2c, 0xFB, 0, &zero);
198 pm860x_write_device(i2c, 0xFF, 0, &zero); 241 read_device(i2c, 0xFF, 0, &zero);
199 ret = pm860x_write_device(i2c, reg, count, buf); 242 ret = write_device(i2c, reg, count, buf);
200 pm860x_write_device(i2c, 0xFE, 0, &zero); 243 read_device(i2c, 0xFE, 0, &zero);
201 pm860x_write_device(i2c, 0xFC, 0, &zero); 244 read_device(i2c, 0xFC, 0, &zero);
202 mutex_unlock(&chip->io_lock); 245 i2c_unlock_adapter(i2c->adapter);
246 i2c_unlock_adapter(i2c->adapter);
203 return ret; 247 return ret;
204} 248}
205EXPORT_SYMBOL(pm860x_page_bulk_write); 249EXPORT_SYMBOL(pm860x_page_bulk_write);
@@ -207,25 +251,24 @@ EXPORT_SYMBOL(pm860x_page_bulk_write);
207int pm860x_page_set_bits(struct i2c_client *i2c, int reg, 251int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
208 unsigned char mask, unsigned char data) 252 unsigned char mask, unsigned char data)
209{ 253{
210 struct pm860x_chip *chip = i2c_get_clientdata(i2c);
211 unsigned char zero; 254 unsigned char zero;
212 unsigned char value; 255 unsigned char value;
213 int ret; 256 int ret;
214 257
215 mutex_lock(&chip->io_lock); 258 i2c_lock_adapter(i2c->adapter);
216 pm860x_write_device(i2c, 0xFA, 0, &zero); 259 read_device(i2c, 0xFA, 0, &zero);
217 pm860x_write_device(i2c, 0xFB, 0, &zero); 260 read_device(i2c, 0xFB, 0, &zero);
218 pm860x_write_device(i2c, 0xFF, 0, &zero); 261 read_device(i2c, 0xFF, 0, &zero);
219 ret = pm860x_read_device(i2c, reg, 1, &value); 262 ret = read_device(i2c, reg, 1, &value);
220 if (ret < 0) 263 if (ret < 0)
221 goto out; 264 goto out;
222 value &= ~mask; 265 value &= ~mask;
223 value |= data; 266 value |= data;
224 ret = pm860x_write_device(i2c, reg, 1, &value); 267 ret = write_device(i2c, reg, 1, &value);
225out: 268out:
226 pm860x_write_device(i2c, 0xFE, 0, &zero); 269 read_device(i2c, 0xFE, 0, &zero);
227 pm860x_write_device(i2c, 0xFC, 0, &zero); 270 read_device(i2c, 0xFC, 0, &zero);
228 mutex_unlock(&chip->io_lock); 271 i2c_unlock_adapter(i2c->adapter);
229 return ret; 272 return ret;
230} 273}
231EXPORT_SYMBOL(pm860x_page_set_bits); 274EXPORT_SYMBOL(pm860x_page_set_bits);