aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Ryjkov <olegr@olegr.ca>2007-10-13 17:56:33 -0400
committerJean Delvare <khali@hyperion.delvare>2007-10-13 17:56:33 -0400
commit4153549734cbdba24e9cf5eb200b70b7b1572e15 (patch)
tree0a68ced86dd6a50f14269f4fa1648f9731036dae
parenta202707e71ff16d5e3a92f40eeaa41f3099dd8c5 (diff)
i2c-nforce2: Move status checking to a separate function
This is the first part of the patch that adds a function to reset the nvidia MCP51/55 i2c controller, if something bad happens to it (e.g. a slave sends a wrong byte count during a block transaction). This patch just adds nforce2_check_status function. It was originally written by Hans-Frieder Vogt. The reason that I'm the one sending it is: - I relied on it for the second part of the patch, - It makes the driver code cleaner/better. Signed-off-by: Oleg Ryjkov <olegr@olegr.ca> Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index c48140f782d0..1c63c4f2e4b6 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -98,15 +98,40 @@ struct nforce2_smbus {
98#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a 98#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
99#define NVIDIA_SMB_PRTCL_PEC 0x80 99#define NVIDIA_SMB_PRTCL_PEC 0x80
100 100
101/* Misc definitions */
102#define MAX_TIMEOUT 100
103
101static struct pci_driver nforce2_driver; 104static struct pci_driver nforce2_driver;
102 105
106static int nforce2_check_status(struct i2c_adapter *adap)
107{
108 struct nforce2_smbus *smbus = adap->algo_data;
109 int timeout = 0;
110 unsigned char temp;
111
112 do {
113 msleep(1);
114 temp = inb_p(NVIDIA_SMB_STS);
115 } while ((!temp) && (timeout++ < MAX_TIMEOUT));
116
117 if (timeout >= MAX_TIMEOUT) {
118 dev_dbg(&adap->dev, "SMBus Timeout!\n");
119 return -1;
120 }
121 if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
122 dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
123 return -1;
124 }
125 return 0;
126}
127
103/* Return -1 on error */ 128/* Return -1 on error */
104static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, 129static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
105 unsigned short flags, char read_write, 130 unsigned short flags, char read_write,
106 u8 command, int size, union i2c_smbus_data * data) 131 u8 command, int size, union i2c_smbus_data * data)
107{ 132{
108 struct nforce2_smbus *smbus = adap->algo_data; 133 struct nforce2_smbus *smbus = adap->algo_data;
109 unsigned char protocol, pec, temp; 134 unsigned char protocol, pec;
110 u8 len; 135 u8 len;
111 int i; 136 int i;
112 137
@@ -170,21 +195,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
170 outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); 195 outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
171 outb_p(protocol, NVIDIA_SMB_PRTCL); 196 outb_p(protocol, NVIDIA_SMB_PRTCL);
172 197
173 temp = inb_p(NVIDIA_SMB_STS); 198 if (nforce2_check_status(adap))
174
175 if (~temp & NVIDIA_SMB_STS_DONE) {
176 udelay(500);
177 temp = inb_p(NVIDIA_SMB_STS);
178 }
179 if (~temp & NVIDIA_SMB_STS_DONE) {
180 msleep(10);
181 temp = inb_p(NVIDIA_SMB_STS);
182 }
183
184 if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
185 dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp);
186 return -1; 199 return -1;
187 }
188 200
189 if (read_write == I2C_SMBUS_WRITE) 201 if (read_write == I2C_SMBUS_WRITE)
190 return 0; 202 return 0;
@@ -202,7 +214,12 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
202 214
203 case I2C_SMBUS_BLOCK_DATA: 215 case I2C_SMBUS_BLOCK_DATA:
204 len = inb_p(NVIDIA_SMB_BCNT); 216 len = inb_p(NVIDIA_SMB_BCNT);
205 len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); 217 if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
218 dev_err(&adap->dev, "Transaction failed "
219 "(received block size: 0x%02x)\n",
220 len);
221 return -1;
222 }
206 for (i = 0; i < len; i++) 223 for (i = 0; i < len; i++)
207 data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); 224 data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
208 data->block[0] = len; 225 data->block[0] = len;